There're lots of rvalue related quiestion but I didn't found answers to these exact questions.
I can't wrap my mind around "named reference is a lvalue reference" rule of thumb.
It seems really strange -- we declare the reference as an rvalue but since we have to somehow use this reference (otherwise, what's the point?), we name it and since it's named it's an lvalue after all!
Consider this code:
int&& foo(int&& arg)
{
arg = 10;
return arg; // ERROR, `arg` is an lvalue since it's named!
}
foo(1);
The questions are:
arg
-s converted from int&&
to int&
and then tries to implicitly convert int&
to int&&
which causes compilation error -- just the opposite behaviour! That's why we need std::move
which is basicaly an explicit static_cast to rvalue type.arg
the variable has type int&&
and no value category.
arg
the expression (it is an expression at lines 3 and 4) has type int
and value category "lvalue"
Lvalue to rvalue conversion changes the value category of an expression, without changing its type. If you write arg+1
inside the function, the lvalue expression arg
of type int
would undergo this conversion to produce a prvalue expression of type int
, since that's what built-in +
requires.
There are no "lvalue to rvalue" or reverse conversions between int& and int&& because expressions never have reference types. The error in your program is a failure to bind an rvalue reference (of type int&&) to an lvalue expression (of type int
).