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
,否则不会执行任何操作