General topics | ||||||||||||||||
Flow control | ||||||||||||||||
Conditional execution statements | ||||||||||||||||
Iteration statements (loops) | ||||||||||||||||
Jump statements | ||||||||||||||||
Functions | ||||||||||||||||
Function declaration | ||||||||||||||||
Lambda function expression | ||||||||||||||||
inline specifier | ||||||||||||||||
Dynamic exception specifications(until C++17*) | ||||||||||||||||
noexcept specifier(C++11) | ||||||||||||||||
Exceptions | ||||||||||||||||
Namespaces | ||||||||||||||||
Types | ||||||||||||||||
Specifiers | ||||||||||||||||
| ||||||||||||||||
Storage duration specifiers | ||||||||||||||||
Initialization | ||||||||||||||||
Expressions | ||||||||||||||||
| ||||||||||||||||
Alternative representations | ||||||||||||||||
Literals | ||||||||||||||||
Boolean -Integer -Floating-point | ||||||||||||||||
Character -String -nullptr(C++11) | ||||||||||||||||
User-defined(C++11) | ||||||||||||||||
Utilities | ||||||||||||||||
Attributes(C++11) | ||||||||||||||||
Types | ||||||||||||||||
typedef declaration | ||||||||||||||||
Type alias declaration(C++11) | ||||||||||||||||
Casts | ||||||||||||||||
Memory allocation | ||||||||||||||||
Classes | ||||||||||||||||
Class-specific function properties | ||||||||||||||||
| ||||||||||||||||
Special member functions | ||||||||||||||||
Templates | ||||||||||||||||
Miscellaneous | ||||||||||||||||
General | |||||||||||||||||||||
| |||||||||||||||||||||
Literals | |||||||||||||||||||||
Operators | |||||||||||||||||||||
Conversions | |||||||||||||||||||||
Each C++expression (an operator with its operands, a literal, a variable name, etc.) is characterized by two independent properties: atype and avalue category. Each expression has some non-reference type, and each expression belongs to exactly one of the three primary value categories:prvalue,xvalue, andlvalue.
decltype
;Extended content |
---|
So-called, historically, because lvalues could appear on the left-hand side of an assignment expression. In general, it's not always the case: void foo(); void baz(){int a;// Expression `a` is lvalue a=4;// OK, could appear on the left-hand side of an assignment expression int&b{a};// Expression `b` is lvalue b=5;// OK, could appear on the left-hand side of an assignment expression constint&c{a};// Expression `c` is lvalue c=6;// ill-formed, assignment of read-only reference // Expression `foo` is lvalue// address may be taken by built-in address-of operatorvoid(*p)()=&foo; foo= baz;// ill-formed, assignment of function} |
Extended content |
---|
So-called, historically, because rvalues could appear on the right-hand side of an assignment expression. In general, it's not always the case: Run this code #include <iostream> struct S{ S(): m{42}{} S(int a): m{a}{}int m;}; int main(){ S s; // Expression `S{}` is prvalue// May appear on the right-hand side of an assignment expression s= S{}; std::cout<< s.m<<'\n'; // Expression `S{}` is prvalue// Can be used on the left-hand side toostd::cout<<(S{}= S{7}).m<<'\n';} Output: 427 |
Note: this taxonomy went through significant changes with past C++ standard revisions, seeHistory below for details.
Extended content |
---|
Despite their names, these terms classify expressions, not values. Run this code #include <type_traits>#include <utility> template<class T>struct is_prvalue:std::true_type{};template<class T>struct is_prvalue<T&>:std::false_type{};template<class T>struct is_prvalue<T&&>:std::false_type{}; template<class T>struct is_lvalue:std::false_type{};template<class T>struct is_lvalue<T&>:std::true_type{};template<class T>struct is_lvalue<T&&>:std::false_type{}; template<class T>struct is_xvalue:std::false_type{};template<class T>struct is_xvalue<T&>:std::false_type{};template<class T>struct is_xvalue<T&&>:std::true_type{}; int main(){int a{42};int& b{a};int&& r{std::move(a)}; // Expression `42` is prvalue static_assert(is_prvalue<decltype((42))>::value); // Expression `a` is lvalue static_assert(is_lvalue<decltype((a))>::value); // Expression `b` is lvalue static_assert(is_lvalue<decltype((b))>::value); // Expression `std::move(a)` is xvalue static_assert(is_xvalue<decltype((std::move(a)))>::value); // Type of variable `r` is rvalue reference static_assert(std::is_rvalue_reference<decltype(r)>::value); // Type of variable `b` is lvalue reference static_assert(std::is_lvalue_reference<decltype(b)>::value); // Expression `r` is lvalue static_assert(is_lvalue<decltype((r))>::value);} |
Contents |
The following expressions arelvalue expressions:
Extended content |
---|
void foo(){} void baz(){// `foo` is lvalue// address may be taken by built-in address-of operatorvoid(*p)()=&foo;} struct foo{}; template<foo a>void baz(){const foo* obj=&a;// `a` is an lvalue, template parameter object} |
Extended content |
---|
int& a_ref(){staticint a{3};return a;} void foo(){ a_ref()=5;// `a_ref()` is lvalue, function call whose return type is lvalue reference} |
m
is a member enumerator or a non-static member function, or wherea is an rvalue andm
is a non-static data member of object type;Extended content |
---|
struct foo{enum bar{ m// member enumerator};}; void baz(){ foo a; a.m=42;// ill-formed, lvalue required as left operand of assignment} struct foo{void m(){}// non-static member function}; void baz(){ foo a; // `a.m` is a prvalue, hence the address cannot be taken by built-in// address-of operatorvoid(foo::*p1)()=&a.m;// ill-formed void(foo::*p2)()=&foo::m;// OK: pointer to member function} struct foo{staticvoid m(){}// static member function}; void baz(){ foo a;void(*p1)()=&a.m;// `a.m` is an lvaluevoid(*p2)()=&foo::m;// the same} |
m
is a member enumerator or a non-static member function;mp
is a pointer to data member;mp
is a pointer to data member;template<int& v>void set(){ v=5;// template parameter is lvalue} int a{3};// static variable, fixed address is known at compile-time void foo(){ set<a>();}
| (since C++11) |
Properties:
The following expressions areprvalue expressions:
m
is a member enumerator or a non-static member function[2];m
is a member enumerator or a non-static member function[2];mp
is a pointer to member function[2];mp
is a pointer to member function[2];this
pointer;template<int v>void foo(){// not an lvalue, `v` is a template parameter of scalar type intconstint* a=&v;// ill-formed v=3;// ill-formed: lvalue required as left operand of assignment}
| (since C++11) |
| (since C++20) |
Properties:
decltype
specifier).The following expressions arexvalue expressions:
m
is a non-static data member of an object type;mp
is a pointer to data member;
| (since C++11) |
| (since C++17) |
(since C++23) |
Properties:
In particular, like all rvalues, xvalues bind to rvalue references, and like all glvalues, xvalues may bepolymorphic, and non-class xvalues may becv-qualified.
Extended content |
---|
Run this code #include <type_traits> template<class T>struct is_prvalue:std::true_type{};template<class T>struct is_prvalue<T&>:std::false_type{};template<class T>struct is_prvalue<T&&>:std::false_type{}; template<class T>struct is_lvalue:std::false_type{};template<class T>struct is_lvalue<T&>:std::true_type{};template<class T>struct is_lvalue<T&&>:std::false_type{}; template<class T>struct is_xvalue:std::false_type{};template<class T>struct is_xvalue<T&>:std::false_type{};template<class T>struct is_xvalue<T&&>:std::true_type{}; // Example from C++23 standard: 7.2.1 Value category [basic.lval]struct A{int m;}; A&& operator+(A, A);A&& f(); int main(){ A a; A&& ar=static_cast<A&&>(a); // Function call with return type rvalue reference is xvalue static_assert(is_xvalue<decltype((f()))>::value); // Member of object expression, object is xvalue, `m` is a non-static data member static_assert(is_xvalue<decltype((f().m))>::value); // A cast expression to rvalue reference static_assert(is_xvalue<decltype((static_cast<A&&>(a)))>::value); // Operator expression, whose return type is rvalue reference to object static_assert(is_xvalue<decltype((a+ a))>::value); // Expression `ar` is lvalue, `&ar` is valid static_assert(is_lvalue<decltype((ar))>::value);[[maybe_unused]] A* ap=&ar;} |
Aglvalue expression is either lvalue or xvalue.
Properties:
Anrvalue expression is either prvalue or xvalue.
Properties:
| (since C++11) |
The expressionsa.mf andp->mf, wheremf
is anon-static member function, and the expressionsa.*pmf andp->*pmf, wherepmf
is apointer to member function, are classified as prvalue expressions, but they cannot be used to initialize references, as function arguments, or for any purpose at all, except as the left-hand argument of the function call operator, e.g.(p->*pmf)(args).
Function call expressions returningvoid, cast expressions tovoid, andthrow-expressions are classified as prvalue expressions, but they cannot be used to initialize references or as function arguments. They can be used in discarded-value contexts (e.g. on a line of its own, as the left-hand operand of the comma operator, etc.) and in thereturn statement in a function returningvoid. In addition, throw-expressions may be used as the second and the third operands of theconditional operator ?:.
Void expressions have noresult object. | (since C++17) |
An expression that designates abit-field (e.g.a.m, wherea is an lvalue of typestruct A{int m:3;}) is a glvalue expression: it may be used as the left-hand operand of the assignment operator, but its address cannot be taken and a non-const lvalue reference cannot be bound to it. A const lvalue reference or rvalue reference can be initialized from a bit-field glvalue, but a temporary copy of the bit-field will be made: it won't bind to the bit-field directly.
Move-eligible expressionsAlthough an expression consisting of the name of any variable is an lvalue expression, such expression may be move-eligible if it appears as the operand of If an expression is move-eligible, it is treatedeither as an rvalue or as an lvalue(until C++23)as an rvalue(since C++23) for the purpose ofoverload resolution (thus it may select themove constructor). SeeAutomatic move from local variables and parameters for details. | (since C++11) |
The programming languageCPL was first to introduce value categories for expressions: all CPL expressions can be evaluated in "right-hand mode", but only certain kinds of expression are meaningful in "left-hand mode". When evaluated in right-hand mode, an expression is regarded as being a rule for the computation of a value (the right-hand value, orrvalue). When evaluated in left-hand mode an expression effectively gives an address (the left-hand value, orlvalue). "Left" and "Right" here stood for "left of assignment" and "right of assignment".
The C programming language followed a similar taxonomy, except that the role of assignment was no longer significant: C expressions are categorized between "lvalue expressions" and others (functions and non-object values), where "lvalue" means an expression that identifies an object, a "locator value"[4].
Pre-2011 C++ followed the C model, but restored the name "rvalue" to non-lvalue expressions, made functions into lvalues, and added the rule that references can bind to lvalues, but only references to const can bind to rvalues. Several non-lvalue C expressions became lvalue expressions in C++.
With the introduction of move semantics in C++11, value categories were redefined to characterize two independent properties of expressions[5]:
In C++11, expressions that:
The expressions that have identity are called "glvalue expressions" (glvalue stands for "generalized lvalue"). Both lvalues and xvalues are glvalue expressions.
The expressions that can be moved from are called "rvalue expressions". Both prvalues and xvalues are rvalue expressions.
In C++17,copy elision was made mandatory in some situations, and that required separation of prvalue expressions from the temporary objects initialized by them, resulting in the system we have today. Note that, in contrast with the C++11 scheme, prvalues are no longer moved from.
T&&
overloads, but they bind to theconst T&& overloads, which are also classified as "move constructor" and "move assignment operator" by the standard, satisfying the definition of "can be moved from" for the purpose of this classification. However, such overloads cannot modify their arguments and are not used in practice; in their absence const prvalues and const xvalues bind toconst T& overloads.The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
CWG 616 | C++11 | member access and member access through pointer to member of an rvalue resulted in prvalue | reclassified as xvalue |
CWG 1059 | C++11 | array prvalues could not be cv-qualified | allowed |
CWG 1213 | C++11 | subscripting an array rvalue resulted in lvalue | reclassified as xvalue |
C documentation forvalue categories |
1. | C++ value categories and decltype demystified — David Mazières, 2021 | |
2. | Empirically determine value category of expression — StackOverflow |