#
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]
2
#
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:
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 + a are 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 void has 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]
Unless otherwise specified ([expr.reinterpret.cast], [expr.const.cast]), whenever a prvalue that is not the result of the lvalue-to-rvalue conversion ([conv.lval]) appears as an operand of an operator, the temporary materialization conversion is applied to convert the expression to an xvalue.
[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.
— end note]
An lvalue is modifiable unless its type is const-qualified or is a function type.
[Note 10: 
A program that attempts to modify an object through a nonmodifiable lvalue or through an rvalue is ill-formed ([expr.assign], [expr.post.incr], [expr.pre.incr]).
— end note]
An object of dynamic 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.38
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]
38)38)
The intent of this list is to specify those circumstances in which an object can or cannot be aliased.
If an expression initially has the type “reference to T” ([dcl.ref], [dcl.init.ref]), the type is adjusted to T 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”, where T 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 and p2 having types T1 and T2, respectively, where at least one is a pointer or pointer-to-member type or std​::​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 C1” and T2 is “pointer to 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”, and C1 is reference-related to C2 or C2 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” and T2 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 to C1 ([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 and T2;
  • 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 to const 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]
In some contexts, an expression only appears for its side effects.
Such an expression is called a discarded-value expression.
The array-to-pointer and function-to-pointer standard conversions are not applied.
The lvalue-to-rvalue conversion is applied if and only if the expression is a glvalue of volatile-qualified type and it is one of the following:
[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.

Follow Lee on X/Twitter - Father, Husband, Serial builder creating AI, crypto, games & web tools. We are friends :) AI Will Come To Life!

Check out: eBank.nz (Art Generator) | Netwrck.com (AI Tools) | Text-Generator.io (AI API) | BitBank.nz (Crypto AI) | ReadingTime (Kids Reading) | RewordGame | BigMultiplayerChess | WebFiddle | How.nz | Helix AI Assistant