当const引用参数绑定到右值时,它是否保持其“状态”?

时间:2019-03-23 19:51:45

标签: c++ move-semantics rvalue-reference pass-by-const-reference

T为任意类型。考虑一个带有const [左值]引用的函数:

void f(const T &obj);

假设此函数在内部调用另一个函数,该函数具有右值引用重载:

void g(T &&obj);

如果我们将右值传递给f,则将调用g的右值引用重载,还是因为它已经“转换” /绑定到{{1 }}左值参考?

类似地,如果const调用了一个按值接受f实例的函数,

T

void h(T obj); 具有移动构造函数(即T),将调用move构造函数,还是将调用复制构造函数?

总而言之,如果我们想确保在对某个右值调用T(T &&);时,右值引用传递给它,保持其右值“状态”,那么我们是否必须为{{ 1}}?

2 个答案:

答案 0 :(得分:3)

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

您正在谈论的能力正是转发引用存在的原因:这样就可以通过函数调用来保留参数表达式的值类别的复制/移动方面。 f必须成为template<typename T> void f(T&& t);形式的模板,并且在将std::forward传递给g时必须使用int*&

答案 1 :(得分:2)

使用引用的名称作为表达式时,该表达式始终是左值。无论是左值引用还是右值引用。引用是用左值还是右值初始化也没有关系。

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时,右值引用传递给它,保持其右值“状态”,那么我们是否必须为{{ 1}}?

提供过载是一种选择。请注意,在这种情况下,您必须在右值重载中显式调用f

另一个方法是使用转发引用,如Nicol Bolas建议的那样:

std::move

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