mardi 19 décembre 2017

When "taking address of temporary" error gets in a way of clean code

I know this error message was discussed multiple times and reasons behind it are well-known. This questions is about different thing -- how to code a certain pattern (that would be trivial if not for that error).

There is a function void foo(int const*, int const*, int const*) where each parameter is nullptr when related data is not available. I used int, but it could be any type (number of arguments is not fixed either).

With MSVC (or in old days -- with -fpermissive) you could write code like this and it is quite easy on eyes:

int data_source::bar() { ... }

data_source* s1;
data_source* s2;
data_source* s3;
...
foo(
    s1 ? &s1->bar() : nullptr,
    s2 ? &s2->bar() : nullptr,
    s3 ? &s3->bar() : nullptr
);

Now, with modern GCC this fails to compile and -fpermissive doesn't seem to work anymore.

How would you structure this code to do the same while avoiding error? Is there a way to tell compiler "yes, I know but it's ok" (similar to (void)x cast to avoid unused variable warning)?

I came up with two "solutions" (don't like both of them):

template<class T> T const* addr(T const& v) { return &v; }

or even more dangerous:

template<class T> T* addr(T&& v) { return &v; }

this means more typing, harder to read and generally ugly.

This one tries to imitate what compiler is doing behind the scene, but unfortunately leads to way too much typing, one extra comparison (per parameter) and other inefficiencies in generated asm:

optional<int> v1 = [&]{ return s1 ? optional<int>(s1->bar()) : optional<int>(); }();
optional<int> v2 = [&]{ return s2 ? optional<int>(s2->bar()) : optional<int>(); }();
optional<int> v3 = [&]{ return s3 ? optional<int>(s3->bar()) : optional<int>(); }();
foo(
    v1 ? &v1.value() : nullptr,
    v2 ? &v2.value() : nullptr,
    v3 ? &v3.value() : nullptr
);

Aucun commentaire:

Enregistrer un commentaire