C++ 17 Value Category System
-----------------------------
| glvalue | |
-----------------------------
| lvalue | xvalue | prvalue |
-----------------------------
| | rvalue |
-----------------------------
What is xvalue, by definition of lvalue and rvalue
extern T y();
T x = y();
x
is lvalue and y()
is rvalue. For the belowing code
T x = T(y());
x
is still lvalue and expression y()
is still rvalue but the intermediate expression T(...)
is what? If we assign a name to it. The above code becomes
T z = y();
T x = std::move(z);
We can see:
-
z
appears at left side of assignment hence it's a lvalue -
std::move(z)
appears at right hand side of assignment hence it's a rvalue.
Be minded that z
std::move(z)
are equivalence as the exprssion T(...)
in privous code snip,
and here T(...)
has both property of rvalue, and property of lvalue except a name.
In C++17, such expression has a new category called xvalue. An xvalue is a glvalue as well as a rvalue at the same time. This result in:
-
All xvalue must be optimized out, as they have no name and eventually they are only used to initialize a lvalue, this behavior is mandatory
-
Due to all xvalue is optimzied out, C++ 17 is able to allow initialize a object of class T, which is non-copyable and non-movable, from xvalue of T, as all xvalue is optimized out, that object is actually constructed in the same way as the most right side prvalue or T.
struct X
{
X(1);
X(const X &) = delete;
X(X&&) = delete;
};
X make_object()
{
return X{1};
// ^ prvalue, not xvalue because glvalue is not here
}
int main()
{
X x = make_object();
//^ lvalue (and also glvalue)
X y = X(make_object());
// ^ prvalue and implicitically converted to xvalue as it is expected by a glvalue (`y`)
}