2

I've been trying to understand this for years and I still don't get it.

According to a blog I'm reading:

int x; int&& y = x; // Error: cannot bind rvalue reference to lvalue 

OK, so y is an r-value reference. Then:

int&& y = 5; int&& z = y; // Error: y is lvalue 

So now y is an lvalue? y is described as being an r-value reference, but it's also an l-value? So it's an l-value r-value reference? What the hell?

14
  • 5
    Every variable has a name, so is a l-value by itself. Commented Apr 8 at 7:27
  • See value_category for details Commented Apr 8 at 7:28
  • 5
    There is a somewhat confusing, but important, distinction in C++ between "value category" and "type". An "rvalue reference" is reference bound to an rvalue, not a reference that is an rvalue. Commented Apr 8 at 7:29
  • 3
    Does this answer stackoverflow.com/a/64089012 help? Commented Apr 8 at 7:53
  • 4
    This is one of the best explanations of value categories I know of: Back to basics: Understanding Value Categories - Ben Saks - CppCon 2019 - I highly recommend watching the video. Commented Apr 8 at 9:10

1 Answer 1

5

An object's Value Category and its Type are two different things. Refer to cppreference.com for more detail. But, in most cases if a variable has a name you can refer to then its Value Category is lvalue when used in an expression:

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 (but see Move-eligible expressions);
  • ...

In this code:

int x; int&& y = x; // Error: cannot bind rvalue reference to lvalue 

x names an object of type int.

y names an object of type int&&, ie reference to rvalue int.

When x is referred to in the expression that initializes y, x is an lvalue, so y's reference cannot be bound to x's object.


In this code:

int&& y = 5; int&& z = y; // Error: y is lvalue 

y and z both name objects of type int&&, ie reference to rvalue int.

5 is a literal. To bind a reference to a literal, the compiler has to first produce a temporary object to hold the literal's value.

When the literal is referred to in the expression that initializes the temporary, the literal is a prvalue. When the temporary is then referred to in the expression that initializes y, the temporary is an xvalue, and since an xvalue is a type of rvalue then y's reference can be bound to the temporary (and the reference will extend the temporary's lifetime).

But, when y is referred to in the expression that initializes z, y is itself an lvalue, so z's reference cannot be bound to y's object.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.