转发引用不是被推导为 r 值引用吗?

0xF*_*0xF 4 c++ perfect-forwarding c++11 forwarding-reference

我有一个关于转发引用的具体问题。(我认为)我理解 r 值引用和std::move,但我无法理解转发引用:

#include <iostream>
#include <utility>

template <typename T> class TD; // from "Effective Modern C++"

void consume(const int &i) { std::cout << "lvalue\n"; }
void consume(int &&i)      { std::cout << "rvalue\n"; }

template <typename T>
void foo(T&& x) {
//    TD<decltype(x)> xType; - prints int&&
    consume(x);
}

int main() {
    foo(1 + 2);
}
Run Code Online (Sandbox Code Playgroud)

Tint,没关系。如果x是 type int&&,为什么它打印“lvalue”而我们需要std::forward?我的意思是,从哪里转换int&&const int&这里?

son*_*yao 5

类型和值类别是表达式的两个独立属性。

每个 C++表达式(带有操作数的运算符、文字、变量名称等)都具有两个独立的属性:类型值类别。每个表达式都有一些非引用类型,每个表达式都属于三个主要值类别之一:prvaluexvaluelvalue

xis的类型int&&,但是x是变量的名称并且x是一个左值表达式本身,它不能绑定到int&&(但可以绑定到const int&)。

(强调我的)

以下表达式是左值表达式

  • 变量、函数, a template parameter object (since C++20)或数据成员的名称,与类型无关,例如std::cinstd::endl即使变量的类型是右值引用,由其名称组成的表达式也是左值表达式

这意味着当函数同时具有左值引用和右值引用重载时,重载决议中也会考虑值类别。

更重要的是,当一个函数同时具有右值引用和左值引用重载时,右值引用重载绑定到右值(包括右值和 xvalues),而左值引用重载绑定到左值:

如果任何参数具有引用类型,则在这一步考虑引用绑定:如果右值参数对应于非常量左值引用参数或左值参数对应于右值引用参数,则该函数不可行。

std::forward用于转换为右值或左值,与转发引用参数的原始值类别一致。当左值int传递给 时fooT推导为int&std::forward<T>(x)则将是一个左值表达式;当右值int传递给 时fooT推导出为intstd::forward<T>(x)则将是一个右值表达式。Sostd::forward可用于保留原始转发引用参数的值类别。相比之下,std::move总是将参数转换为右值表达式。