Reputation: 993
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
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
orstd::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 ofstd::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