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.