Search code examples
c++c++11rvalue-reference

Rvalue to lvalue conversion and "named-refs-are-lvalues" rule


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:

  1. When exactly does arg become an lvalue?
  2. What would be the type of arg if the function was void and b) and c) lines were not present?
  3. Lot's of articles (just citing first found result) say that there may be implicit lvalue to rvalue conversion but the opposite direction is not possible -- why? This example shows that 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.

Solution

  • 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).