[expr.prop] (original) (raw)
7.2.1 Value category [basic.lval]
Expressions are categorized according to the taxonomy in Figure 2.
categories expression expression glvalue glvalue expression->glvalue rvalue rvalue expression->rvalue lvalue lvalue glvalue->lvalue xvalue xvalue glvalue->xvalue rvalue->xvalue prvalue prvalue rvalue->prvalue
Figure 2 — Expression category taxonomy [fig:basic.lval]
- A glvalue is an expression whose evaluation determines the identity of an object or function.
- A prvalue is an expression whose evaluation initializes an object or computes the value of an operand of an operator, as specified by the context in which it appears, or an expression that has type cv void.
- An xvalue is a glvalue that denotes an object whose resources can be reused (usually because it is near the end of its lifetime).
- An lvalue is a glvalue that is not an xvalue.
- An rvalue is a prvalue or an xvalue.
Every expression belongs to exactly one of the fundamental categories in this taxonomy: lvalue, xvalue, or prvalue.
This property of an expression is called its value category.
[Note 1:
The discussion of each built-in operator in[expr.compound] indicates the category of the value it yields and the value categories of the operands it expects.
For example, the built-in assignment operators expect that the left operand is an lvalue and that the right operand is a prvalue and yield an lvalue as the result.
User-defined operators are functions, and the categories of values they expect and yield are determined by their parameter and return types.
— _end note_]
[Note 2:
Historically, lvalues and rvalues were so-called because they could appear on the left- and right-hand side of an assignment (although this is no longer generally true); glvalues are “generalized” lvalues, prvalues are “pure” rvalues, and xvalues are “eXpiring” lvalues.
Despite their names, these terms apply to expressions, not values.
— _end note_]
[Note 3:
An expression is an xvalue if it is:
- a move-eligible id-expression ([expr.prim.id.unqual]),
- the result of calling a function, whether implicitly or explicitly, whose return type is an rvalue reference to object type ([expr.call]),
- a cast to an rvalue reference to object type ([expr.type.conv], [expr.dynamic.cast], [expr.static.cast], [expr.reinterpret.cast], [expr.const.cast], [expr.cast]),
- a subscripting operation with an xvalue array operand ([expr.sub]),
- a class member access expression designating a non-static data member of non-reference type in which the object expression is an xvalue ([expr.ref]), or
- a .* pointer-to-member expression in which the first operand is an xvalue and the second operand is a pointer to data member ([expr.mptr.oper]).
In general, the effect of this rule is that named rvalue references are treated as lvalues and unnamed rvalue references to objects are treated as xvalues; rvalue references to functions are treated as lvalues whether named or not.
— _end note_]
[Example 1: struct A { int m;}; A&& operator+(A, A); A&& f(); A a; A&& ar = static_cast<A&&>(a);
The expressions f(), f().m, static_cast<A&&>(a), and a + aare xvalues.
The expression ar is an lvalue.
— _end example_]
The result of a glvalue is the entity denoted by the expression.
The result of a prvalue is the value that the expression stores into its context; a prvalue that has type cv void has no result.
A prvalue whose result is the value _V_is sometimes said to have or name the value V.
The result object of a prvalue is the object initialized by the prvalue; a prvalue that has type cv voidhas no result object.
[Note 4:
Except when the prvalue is the operand of a decltype-specifier, a prvalue of object type always has a result object.
For a discarded prvalue that has type other than cv void, a temporary object is materialized; see [expr.context].
— _end note_]
Whenever a glvalue appears as an operand of an operator that requires a prvalue for that operand, the lvalue-to-rvalue ([conv.lval]), array-to-pointer ([conv.array]), or function-to-pointer ([conv.func]) standard conversions are applied to convert the expression to a prvalue.
[Note 5:
An attempt to bind an rvalue reference to an lvalue is not such a context; see [dcl.init.ref].
— _end note_]
[Note 6:
Because cv-qualifiers are removed from the type of an expression of non-class type when the expression is converted to a prvalue, an lvalue of type const int can, for example, be used where a prvalue of type int is required.
— _end note_]
[Note 7:
There are no prvalue bit-fields; if a bit-field is converted to a prvalue ([conv.lval]), a prvalue of the type of the bit-field is created, which might then be promoted ([conv.prom]).
— _end note_]
[Note 8:
The discussion of reference initialization in [dcl.init.ref] and of temporaries in [class.temporary] indicates the behavior of lvalues and rvalues in other significant contexts.
— _end note_]
Unless otherwise indicated ([dcl.type.decltype]), a prvalue shall always have complete type or the void type; if it has a class type or (possibly multidimensional) array of class type, that class shall not be an abstract class ([class.abstract]).
A glvalue shall not have type cv void.
[Note 9:
A glvalue can have complete or incomplete non-void type.
Class and array prvalues can have cv-qualified types; other prvalues always have cv-unqualified types.
See [expr.type].
— _end note_]
An lvalue is modifiable unless its type is const-qualified or is a function type.
An object of dynamic type istype-accessible through a glvalue of type if is similar ([conv.qual]) to:
- ,
- a type that is the signed or unsigned type corresponding to , or
- a char, unsigned char, or std::byte type.
If a program attempts to access ([defns.access]) the stored value of an object through a glvalue through which it is not type-accessible, the behavior is undefined.42
If a program invokes a defaulted copy/move constructor or copy/move assignment operator for a union of type U with a glvalue argument that does not denote an object of type cv U within its lifetime, the behavior is undefined.
[Note 11:
In C, an entire object of structure type can be accessed, e.g., using assignment.
By contrast, C++ has no notion of accessing an object of class type through an lvalue of class type.
— _end note_]
7.2.2 Type [expr.type]
If an expression initially has the type “reference toT” ([dcl.ref], [dcl.init.ref]), the type is adjusted toT prior to any further analysis; the value category of the expression is not altered.
Let X be the object or function denoted by the reference.
If a pointer to X would be valid in the context of the evaluation of the expression ([basic.fundamental]), the result designates X; otherwise, the behavior is undefined.
[Note 1:
Before the lifetime of the reference has started or after it has ended, the behavior is undefined (see [basic.life]).
— _end note_]
If a prvalue initially has the type “cv T”, whereT is a cv-unqualified non-class, non-array type, the type of the expression is adjusted to T prior to any further analysis.
The composite pointer type of two operands p1 andp2 having types T1 and T2, respectively, where at least one is a pointer or pointer-to-member type orstd::nullptr_t, is:
- if both p1 and p2 are null pointer constants,std::nullptr_t;
- if either p1 or p2 is a null pointer constant, T2 or T1, respectively;
- if T1 or T2 is “pointer to cv1 void” and the other type is “pointer to cv2 T”, where T is an object type or void, “pointer to cv12 void”, where cv12 is the union of cv1 and cv2;
- if T1 or T2 is “pointer to noexcept function” and the other type is “pointer to function”, where the function types are otherwise the same, “pointer to function”;
- if T1 is “pointer to cv1 C1” and T2 is “pointer to_cv2_ C2”, where C1 is reference-related to C2 or C2 is reference-related to C1 ([dcl.init.ref]), the qualification-combined type ([conv.qual]) of T1 and T2 or the qualification-combined type of T2 and T1, respectively;
- if T1 or T2 is “pointer to member of C1 of type function”, the other type is “pointer to member of C2 of type noexcept function”, andC1 is reference-related to C2 orC2 is reference-related to C1 ([dcl.init.ref]), where the function types are otherwise the same, “pointer to member of C2 of type function” or “pointer to member of C1 of type function”, respectively;
- if T1 is “pointer to member of C1 of type cv1 U” andT2 is “pointer to member of C2 of type cv2 U”, for some non-function type U, where C1 is reference-related to C2 or C2 is reference-related toC1 ([dcl.init.ref]), the qualification-combined type of T2 and T1 or the qualification-combined type of T1 and T2, respectively;
- if T1 and T2 are similar types ([conv.qual]), the qualification-combined type of T1 andT2;
- otherwise, a program that necessitates the determination of a composite pointer type is ill-formed.
[Example 1: typedef void *p;typedef const int *q;typedef int **pi;typedef const int **pci;
The composite pointer type of p and q is “pointer to const void”; the composite pointer type of pi and pci is “pointer to const pointer toconst int”.
— _end example_]
7.2.3 Context dependence [expr.context]
An unevaluated operand is not evaluated.
[Note 1:
In an unevaluated operand, a non-static class member can be named ([expr.prim.id]) and naming of objects or functions does not, by itself, require that a definition be provided ([basic.def.odr]).
An unevaluated operand is considered a full-expression.
— _end note_]
[Note 2:
Using an overloaded operator causes a function call; the above covers only operators with built-in meaning.
— _end note_]
The temporary materialization conversion ([conv.rval]) is applied if the (possibly converted) expression is a prvalue of object type.
[Note 3:
If the original expression is an lvalue of class type, it must have a volatile copy constructor to initialize the temporary object that is the result object of the temporary materialization conversion.
— _end note_]
The expression is evaluated and its result (if any) is discarded.