将右值引用绑定(bind)到给定对象或其临时拷贝的最佳方法是什么?
A &&var_or_dummy = modify? static_cast<A&&>( my_A )
: static_cast<A&&>( static_cast<A>( my_A ) );
(此代码在我最近的GCC 4.6上不起作用。我记得它以前可以工作,但是现在它总是返回一个拷贝。)
在第一行,
static_cast
将my_A
从左值转换为x值。 (C++ 0x§5.2.9/1-3)第二行的内部static_cast
执行左值到右值转换,而外部的const
从此prvalue获得一个xvalue。这似乎受到支持,因为根据§12.2/5命名的引用有条件地绑定(bind)到临时引用。在带有
move
引用的C++ 03中,相同的技巧以相同的方式工作。我也可以不那么冗长地写同样的东西:
A &&var_or_dummy = modify? std::move( my_A )
: static_cast<A&&>( A( my_A ) );
现在要短得多。第一个缩写是可疑的:
move
旨在表示对象正在发生某些事情,而不仅仅是lvalue-to-xvalue-l-value随机播放。令人困惑的是,不能在:
之后使用A(my_A)
,因为该函数调用会中断临时到引用的绑定(bind)。语法static_cast
也许比static_cast
更清晰,但是从技术上讲,它等效于C风格的强制转换。我也可以一路走下去,完全用C风格的强制转换编写它:
A &&var_or_dummy = modify? (A&&)( my_A ) : (A&&)( A( my_A ) );
毕竟,如果这将成为一种习惯用法,那么它一定很方便,而且
my_A
并不能真正保护我免受任何侵害-真正的危险是在true
情况下无法直接绑定(bind)到A
。另一方面,这很容易被重复三次的类型名所支配。如果将
V
替换为一个大而丑陋的template-id,我真的想要一个真正的捷径。(请注意,尽管ojit_code出现了五次,但它仅被评估一次:)
#define VAR_OR_DUMMY( C, V ) ( (C)? \
static_cast< typename std::remove_reference< decltype(V) >::type && >( V ) \
: static_cast< typename std::remove_reference< decltype(V) >::type && > ( \
static_cast< typename std::remove_reference< decltype(V) >::type >( V ) ) )
我认为宏是骇人听闻的,是这堆中最好的选择。这有点危险,因为它返回一个xvalue,因此不应在引用初始化之外使用它。
一定有我没想到过的东西……建议?
最佳答案
只需通过额外的函数调用来避免整个困惑:
void f(bool modify, A &obj) {
return [&](A &&obj) {
real();
work();
}(modify ? std::move(obj) : std::move(A(obj)));
}
代替:
void f(bool modify, A &obj) {
A &&var_or_dummy = /* ??? */;
real();
work();
}
这是lambdas, lambdas, everywhere!