右引用混淆传递的c ++函数

时间:2018-07-19 11:37:25

标签: c++ function casting pass-by-reference compile-time

我正在看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:

  

移动语义不会自动传递的事实是故意的   和重要。如果不是,那么当我们在函数中第一次使用可移动对象时,它将失去它的值。

我仍然很好奇为什么即使它们具有相同的类型,它们在编译时也会选择不同的功能?

1 个答案:

答案 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);
  •   
  • ...
  •