如何创建一个多次使用一个值而不复制它的宏?

我想创建一个宏,将一对解包成两个局部变量.如果它只是一个变量,我不想创建该对的副本,这将完成:

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);

但是,我也希望它不计算多次给出的表达式,例如这应该只调用一次 expensive_computation():

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());

如果我这样做:

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

那么它适用于 expensive_computation() 情况,但它会在 x 情况下进行复制.如果我这样做:

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;

然后它可以在 x 的情况下工作而不进行复制,但在 expensive_computation() 的情况下会失败.如果我这样做:

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;

<小时>

是否有任何方法可以创建适用于这两种用例的宏 - 既不复制 x 也不在给出表达式或函数调用的结果时调用未定义的行为?


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?

推荐答案

auto&& 创建一个转发引用,即它接受任何东西.它确实不(总是)创建一个右值引用.所以就这样做吧:

auto&& creates a forwarding reference, i.e. it accepts anything. It does not (always) create an rvalue reference. So just do this:

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

但是,我强烈建议不要这样做(除非 UNPACK_PAIR 的使用范围非常有限,并且该操作在该范围内真的无处不在).它看起来默默无闻,对我没有真正的好处.想象一下,在 6 个月后回到项目,只需要两个小时就可以找到一个严重的错误.你会感谢自己使用非标准的基于宏的语法而不是可读的东西吗?

However, I would strongly suggest against this (unless the scope of the use of UNPACK_PAIR is very limited and the operation is really ubiquitous in that scope). It looks like obscurity for no real benefit to me. Imagine returning to the project after 6 months, with just two hours to find a critical bug. Will you be thanking yourself for using a nonstandard macro-based syntax instead of something readable?

相关文章