Martin
Martin

Reputation: 993

C++ - Passing rvalue references to function?

I'm having trouble understanding how rvalue references work. I have the following code:

void f(int&& i)
{}

int main()
{
    int i = 42;
    int&& r = std::move(i);

    f(r);

    return 0;
}

Here, I'm getting the following compiler error:

prog.cpp: In function ‘int main()’:
prog.cpp:46:7: error: cannot bind rvalue reference of type ‘int&&’ to lvalue of type ‘int’
     f(r);
       ^
prog.cpp:38:6: note:   initializing argument 1 of ‘void f(int&&)’
 void f(int&& i)
      ^

Why does the compiler think I'm passing an lvalue, when I explicitly declared r to be an rvalue reference? Doing f(std::move(r)) seems to work, but I still don't understand what's different there.

Is this because, in the f(r) call, r is taken to be an lvalue? If so, what's the type of std::move(r)?

Upvotes: 4

Views: 1169

Answers (1)

songyuanyao
songyuanyao

Reputation: 172894

Types and value categories are two different things.

(emphasis mine)

Each C++ expression (an operator with its operands, a literal, a variable name, etc.) is characterized by two independent properties: a type and a value category.

As a named variable, r is an lvalue, which can't be bound to rvalue-reference.

(emphasis mine)

The following expressions are lvalue expressions:

  • the name of a variable, a function, a template parameter object (since C++20), or a data member, regardless of type, such as std::cin or std::endl. Even if the variable's type is rvalue reference, the expression consisting of its name is an lvalue expression;

On the other hand, std::move(r) is an xvalue, which is a kind of rvalue and could be bound to rvalue-reference.

The following expressions are xvalue expressions:

  • a function call or an overloaded operator expression, whose return type is rvalue reference to object, such as std::move(x);

About your doubt,

Is this because, in the f(r) call, r is taken to be an lvalue? If so, what's the type of std::move(r)?

Yes, r is an lvalue expression, and std::move(r) is an xvalue (rvalue) expression; even both the type is rvalue-reference, i.e. int&&.

Upvotes: 7

Related Questions