[英]Does an rvalue keep its “status” when a const reference parameter binds to it?
令T
为任意类型。 考虑一个采用const
[lvalue]引用的const
:
void f(const T &obj);
假设此函数在内部调用另一个函数,该函数具有右值引用重载:
void g(T &&obj);
如果我们将右值传递给f
,会调用g
的右值引用重载,还是因为它已“转换” /绑定到const
左值引用而失败了?
同样,如果f
调用了一个按值接受T
实例的函数,
void h(T obj);
并且T
具有move构造函数(即T(T &&);
),将调用move构造函数,还是将调用copy构造函数?
总而言之,如果我们想确保在对一个右值调用f
时,右值引用在传递时保持其右值“状态”,那么我们是否必须为f
提供右值引用重载?
值类别应用于表达式 ,而不是对象。 f
中的obj
是一个左值表达式,因此将被视为此类。 注意g
中的obj
也是一个左值表达式; 如果表达式是对象的名称,则为左值。
您正在谈论的能力正是转发引用存在的原因:这样就可以通过函数调用来保留参数表达式的值类别的复制/移动方面。 f
必须成为以下形式的template<typename T> void f(T&& t);
,并且在将其传递给g
时必须使用std::forward
。
当您将引用的名称用作表达式时,该表达式始终是左值。 无论是左值引用还是右值引用。 引用是用左值还是右值初始化也无关紧要。
int &&x = 1;
f(x); // Here `x` is lvalue.
因此,在void f(const T &obj) {...}
,不管您作为参数传递什么, obj
始终是左值。
还要注意,值类别是在编译时确定的。 由于f
不是模板,因此其中的每个表达式的值类别都不能取决于您传递的参数。
从而:
如果将rvalue传递给
f
,则将调用g
的rvalue参考重载。
没有。
如果
f
调用了一个按值接受T
实例的函数,则void h(T obj);
并且T
有一个move构造函数(即T(T &&);
),该move构造函数将被称为
没有。
总而言之,如果我们想确保在对一个右值调用
f
时,右值引用在传递时保持其右值“状态”,那么我们是否必须为f
提供右值引用重载?
提供过载是一种选择。 请注意,在这种情况下,您必须在rvalue重载中显式调用std::move
。
另一个选择是使用转发引用 ,如Nicol Bolas建议的那样:
template <typename T> void f(T &&t)
{
g(std::forward<T>(t));
}
在这里, std::forward
本质上是一种“条件move
”。 如果传递了右值,它将移动t
,否则不执行任何操作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.