Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I create a macro which uses a value multiple times, without copying it?

I'd like to create a macro which unpacks a pair into two local variables. I'd like to not create a copy of the pair if it's just a variable, which this would accomplish:

#define UNPACK_PAIR(V1, V2, PAIR) \
    auto& V1 = PAIR.first; \
    auto& V2 = PAIR.second;

UNPACK_PAIR(one, two, x);

However, I'd also like it to not evaluate the expression it's given multiple times, e.g. this should only call expensive_computation() once:

UNPACK_PAIR(one, two, expensive_computation());

If I do:

#define UNPACK_PAIR_A(V1, V2, PAIR) \
    auto tmp = PAIR; \
    auto& V1 = tmp.first; \
    auto& V2 = tmp.second;

then it works for the expensive_computation() case, but it makes a copy in the x case. If I do:

#define UNPACK_PAIR_R(V1, V2, PAIR) \
    auto& tmp = PAIR; \
    auto& V1 = tmp.first; \
    auto& V2 = tmp.second;

Then it works in the x case without making a copy but fails in the expensive_computation() case. If I do:

#define UNPACK_PAIR_CR(V1, V2, PAIR) \
    const auto& tmp = PAIR; \
    auto& V1 = tmp.first; \
    auto& V2 = tmp.second;

#define UNPACK_PAIR_RR(V1, V2, PAIR) \
    auto&& tmp = PAIR; \
    auto& V1 = tmp.first; \
    auto& V2 = tmp.second;

These both compile and run, but I suspect they invoke undefined behavior - am I correct about that? Also, would either of these make any sense?

#define UNPACK_PAIR_RR(V1, V2, PAIR) \
    auto&& tmp = std::move(PAIR); \
    auto& V1 = tmp.first; \
    auto& V2 = tmp.second;

#define UNPACK_PAIR_RR(V1, V2, PAIR) \
    auto&& tmp = std::forward<decltype(PAIR)>(PAIR); \
    auto& V1 = tmp.first; \
    auto& V2 = tmp.second;

Is there any way to create a macro that works for both of these use cases - not copying x yet also not invoking undefined behavior when given the result of an expression or function call?

like image 433
Claudiu Avatar asked Jul 07 '15 15:07

Claudiu


1 Answers

You don't need a macro for this.

auto p = std::make_pair(2, 3);
int x, y;
std::tie(x, y) = p;

If you want references to existing members of a pair:

auto p = std::make_pair(2, 3);
auto& x = p.first;
auto& y = p.second;

That's it.

Now you can move on to something more challenging/interesting/important.

like image 102
Lightness Races in Orbit Avatar answered Oct 22 '22 15:10

Lightness Races in Orbit