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

问题描述 投票:2回答:2

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

void f(const T &obj);

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

void g(T &&obj);

如果我们将rvalue传递给f,是否会调用g的右值引用过载,或者它是否会失败,因为它已被“转换”/绑定到const左值引用?

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

void h(T obj);

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

总之,如果我们想确保在rvalue上调用f时,rvalue引用会保持其rvalue“status”,我们是否必须为f提供rvalue引用重载?

c++ move-semantics rvalue-reference pass-by-const-reference
2个回答
2
投票

当您使用引用的名称作为表达式时,该表达式始终是左值。无论它是左值参考还是右值参考。如果使用左值或右值初始化引用也无关紧要。

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

因此,在void f(const T &obj) {...}中,obj总是一个左值,无论你作为一个论点传递什么。

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

从而:

如果我们将rvalue传递给f,那么将调用g的右值引用过载

没有。

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

没有。

总之,如果我们想确保在rvalue上调用f时,rvalue引用会保持其rvalue“status”,我们是否必须为f提供rvalue引用重载?

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

另一个选择是使用转发引用,正如Nicol Bolas建议的那样:

template <typename T> void f(T &&t)
{
    g(std::forward<T>(t));
}

在这里,std::forward基本上充当'有条件的move'。如果rvalue传递给它,它会移动t,否则什么都不做。


3
投票

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

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

© www.soinside.com 2019 - 2024. All rights reserved.