右值重载?

Overloading for rvalue?

下面是演示问题的代码:

class X {};
X x;
X&& rvalue_ref = std::move(x);
static_assert(std::is_same<decltype(rvalue_ref), X&&>::value, "Different types"); //To be sure that type is X&&
void func(X&) {
    cout << "lvalue reference";
}

void func(X&&) {
    cout << "rvalue reference";
}
int main() {
    func(rvalue_ref);
}

输出:

lvalue reference

能解释一下原因吗?我们有一个 X&& 类型的变量和一个该类型的重载,但未调用该重载。

参考文献并不是那样有效的。你的参数 rvalue_ref,尽管它的类型,是一个 左值表达式 。您必须再次执行 std::move 才能使其成为右值。

类型和值类别是两个独立的事物,很难记住命名 右值引用 类型对象的表达式不会自动成为右值表达式。

另请考虑:

void foo(T&& ref)
{
   bar(ref);             // lvalue arg
   bar(std::move(ref));  // rvalue arg
}

cppreference.com's "Value categories" article上也提到了这个:

Even if the variable's type is rvalue reference, the expression consisting of its name is an lvalue expression

这是完全合理的行为 - 右值引用在 C++ 中是左值。这意味着获得输出

rvalue reference

你必须这样使用 std::move:

int main() {
    func(std::move(rvalue_ref));
}

这在将参数传递给函数时尤其容易混淆。例如,要将参数作为右值传递,您必须使用 std::move:

void foo(bar &&baz) {
    function_taking_rvalue_reference(std::move(baz));// <--- this move is necessary
}