通过正确引用混淆的c ++函数

c++ function that pass by right reference confusion

我正在查看 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++ templates complete guide" 中有一个蛤蜊是:

The fact that move semantics is not automatically passed through is intentional and important. If it weren’t, we would lose the value of a movable object the first time we use it in a function.

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

你混淆了类型和 value categories,它们是不同的东西。

作为命名变量,x的值类别是左值,(它的类型是int&&。)左值可以绑定到左值引用,但不能绑定到右值-参考。因此给定 f1(x);f1(int&) 将被 selected.

要调用 f1(int&&),您需要将其转换为右值。第一个和第二个 select f1(int&&) 因为显式转换会生成右值表达式(更准确地说是 xvalue 表达式);可以绑定到右值引用。 std::move 也以类似的方式工作。

The following expressions are xvalue expressions:

  • a function call or an overloaded operator expression, whose return type is rvalue reference to object, such as std::move(x);
  • ...
  • a cast expression to rvalue reference to object type, such as static_cast<char&&>(x);
  • ...