C++ 右值是否保留其“值”;“地位”;当常量引用参数绑定到它时?

C++ 右值是否保留其“值”;“地位”;当常量引用参数绑定到它时?,c++,move-semantics,rvalue-reference,pass-by-const-reference,C++,Move Semantics,Rvalue Reference,Pass By Const Reference,设T为任意类型。考虑一个函数,使用 const [LVal]引用: void f(const T&obj); 假设此函数在内部调用另一个函数,该函数具有右值引用重载: void g(T&obj); 如果我们将右值传递给f,将调用g的右值引用重载,还是因为它已“转换”/绑定到const左值引用而无法调用 类似地,如果f调用一个函数,该函数按值获取T的一个实例 void h(T obj); 并且T有一个移动构造函数,(即T(T&&);),将调用移动构造函数,还是将调用复制构造函数 总之,如果

T
为任意类型。考虑一个函数,使用<代码> const <代码> [LVal]引用:

void f(const T&obj);
假设此函数在内部调用另一个函数,该函数具有右值引用重载:

void g(T&obj);
如果我们将右值传递给
f
,将调用
g
的右值引用重载,还是因为它已“转换”/绑定到
const
左值引用而无法调用

类似地,如果
f
调用一个函数,该函数按值获取
T
的一个实例

void h(T obj);
并且
T
有一个移动构造函数,(即
T(T&&);
),将调用移动构造函数,还是将调用复制构造函数


总之,如果我们想确保在对右值调用
f
时,右值引用被传递以保持其右值“状态”,那么我们是否必须为
f
提供右值引用重载?

值类别应用于表达式,而不是对象<
f
中的code>obj是一个左值表达式,因此将被视为左值表达式。注意
g
中的
obj
也是一个左值表达式;如果表达式是对象的名称,则它是左值


您所说的这种能力正是转发引用存在的原因:这样就可以通过函数调用保留参数表达式值类别的复制/移动方面<代码>f必须成为格式为
模板void f(T&&T)的模板,将其传递给
g
时必须使用
std::forward
,当使用引用的名称作为表达式时,该表达式始终是左值。不管是左值引用还是右值引用。不管引用是用左值还是右值初始化的,这也无关紧要

int &&x = 1;
f(x); // Here `x` is lvalue.
因此,在
void f(const T&obj){…}
中,
obj
始终是一个左值,而不管作为参数传递什么

还要注意,值类别是在编译时确定的。因为
f
不是模板,所以其中每个表达式的值类别不能依赖于您传递的参数

因此:

如果我们将右值传递给
f
,是否会调用
g
的右值引用重载

没有

如果
f
调用了一个函数,该函数按值取
T
的一个实例,
void h(T obj)
T
具有移动构造函数(即
T(T&&);
),将调用移动构造函数吗

没有

总之,如果我们想确保在对右值调用
f
时,右值引用被传递,以保持其右值“状态”,那么我们是否必须为
f
提供右值引用重载

提供重载是一种选择。注意,在这种情况下,必须在右值重载中显式调用
std::move

另一种选择是使用转发引用,Nicol Bolas建议:

template <typename T> void f(T &&t)
{
    g(std::forward<T>(t));
}
模板无效f(T&T)
{
g(std::forward(t));
}
在这里,
std::forward
实质上充当了一个“有条件的
move
”。如果向它传递了右值,它将移动
t
,否则不会执行任何操作