我正在看std :: move函数的源代码。它的作用是删除引用并添加正确的引用(&&)。
/**
* @brief Convert a value to an rvalue.
* @param __t A thing of arbitrary type.
* @return The parameter cast to an rvalue-reference to allow moving it.
*/
template<typename _Tp>
constexpr typename std::remove_reference<_Tp>::type&&
move(_Tp&& __t) noexcept
{ return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); }
所以,我想知道是否可以做出正确的引用并将其传递给函数?因此,这里是:
void f1(int&&) { std::cout << 1; }
void f1(int&) { std::cout << 2; }
int main() {
int&& x = 1;
f1(static_cast<decltype(x)>(x));
f1(static_cast<int&&>(x));
f1(x);
}
然后,输出:112
我发现x是int &&的类型,因为前两个f1做相同的事情。但是,第三个呢?它不是int &&吗?为什么我必须要static_cast才能将其用作正确的参考? 我知道“ c ++模板完整指南”中有一个蛤lam:
移动语义不会自动传递的事实是故意的 和重要。如果不是,那么当我们在函数中第一次使用可移动对象时,它将失去它的值。
我仍然很好奇为什么即使它们具有相同的类型,它们在编译时也会选择不同的功能?
答案 0 :(得分:4)
您混淆类型和value categories,它们是不同的东西。
作为命名变量,x
的值类别为lvalue,(其类型为int&&
。)lvalues可以绑定到lvalue-reference,但不能绑定到rvalue-reference 。因此,给定f1(x);
,将选择f1(int&)
。
要调用f1(int&&)
,您需要将其转换为右值。第一个和第二个选择f1(int&&)
是因为显式转换生成了右值表达式(更准确地说是右值表达式);可以绑定到右值引用。 std::move
也以类似的方式工作。
以下表达式是xvalue表达式:
- 函数调用或重载的运算符表达式,其返回类型是对对象的右值引用,例如
std::move(x)
;- ...
- 对对象类型进行右值引用的强制转换表达式,例如
static_cast<char&&>(x)
;- ...