C++11:为什么右值引用参数隐式转换为左值

C++11: Why rvalue reference parameter implicitly converted to lvalue

以下是我的问题的简单代码,

void overloaded (int&& x) {
  cout << "[rvalue]";
}

template <class T>
void fn (T&& x) {
  overloaded(x);
}

int main() {
    fn(0);
    return 0;
}

我遇到编译错误

cannot bind ‘int’ lvalue to ‘int&&

  overloaded(x);

我在这里很困惑,x 作为右值引用传递给 fn()。但是为什么 fn() 中的 overload() 调用抱怨 x 是左值?

第一,fnx 参数不是 r-value 引用,it's a "universal reference" (yes, this is rather confusing)。

第二,当你给一个对象一个名字时,这个名字不是 r-value 除非明确地 "fixed",要么用 std::move(使它成为 r-value 引用,总是),或使用 std::forward (在通用引用的情况下将其转换回其原始类型)。如果你想避免被投诉,请使用std::forward转发为原始类型:

template <class T>
void fn (T&& x) {
  overloaded(std::forward<T>(x));
}

你不是 "passing x as an rvalue reference",因为那句话根本说不通。

以下是有关 C++ 中类型和表达式分类的精选事实:

  • 有对象类型,也有引用类型。 (还有其他几种类型。)

  • 变量可以是对象或引用。

  • 表达式有类型,那些类型(几乎)总是对象类型,从不引用。 (这就是为什么你的 "passing something as a reference" 语句没有意义;你传递 参数 并且参数总是表达式。)表达式可以是左值、xvalues 或 prvalues。

  • 左值引用绑定到左值。右值引用绑定到右值。 (右值要么是纯右值,要么是 x 值。)

  • id-expression 命名变量或参数是左值。 (如果您愿意,可以是 "thing with a name" 或 "a location"。)

因此在表达式 overloaded(x) 中,子表达式 x 是一个左值,它不绑定到需要右值的函数(由于其右值引用参数)。

"lvalue reference"和"rvalue reference"中的"l"和"r"是指引用可以绑定的值的类别,不是 到 id-expression 命名此引用类型的变量的类别。

您可以将左值转换为右值,方法是将其转换为亡值;这很方便地封装到 type-deducing cast helper std::move.