2

设为T任意类型。考虑一个采用const[lvalue] 引用的函数:

void f(const T &obj);

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

void g(T &&obj);

如果我们将 rvalue 传递给f,是否会调用 rvalue 引用重载g,还是会因为它已“转换”/绑定到const左值引用而无法调用?

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

void h(T obj);

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

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

4

2 回答 2

3

值类别应用于表达式,而不是对象。objinf是一个左值表达式,因此将被视为左值表达式。注意objing也是一个值表达式;如果表达式是一个对象的名称,那么它就是一个左值。

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

于 2019-03-23T20:04:38.010 回答
2

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

int &&x = 1;
f(x); // Here `x` is lvalue.

所以 in 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));
}

在这里,std::forward基本上充当“条件move”。如果将右值传递给它,它就会移动t,否则什么也不做。

于 2019-03-23T20:07:46.120 回答