Expressions
An expression is a sequence of operators and their operands, that specifies a computation.
Expression evaluation may produce a result (e.g., evaluation of 2 + 2 produces the result 4) and may generate side-effects (e.g. evaluation of std::printf("%d", 4) prints the character '4' on the standard output).
Each C++ expression is characterized by two independent properties: A type and a value category.
General
- value categories (lvalue, rvalue, glvalue, prvalue, xvalue(since C++11)) classify expressions by their values
- order of evaluation of arguments and subexpressions specify the order in which intermediate results are obtained
Operators
Common operators | ||||||
---|---|---|---|---|---|---|
assignment | increment decrement |
arithmetic | logical | comparison | member access |
other |
a = b |
++a |
+a |
!a |
a == b |
a[...] |
function call |
a(...) | ||||||
comma | ||||||
a, b | ||||||
conditional | ||||||
a ? b : c | ||||||
Special operators | ||||||
static_cast converts one type to another related type |
- operator precedence defines the order in which operators are bound to their arguments
- alternative representations are alternative spellings for some operators
- operator overloading makes it possible to specify the behavior of the operators with user-defined classes.
Conversions
- standard conversions implicit conversions from one type to another
-
const_cast
conversion -
static_cast
conversion -
dynamic_cast
conversion -
reinterpret_cast
conversion - explicit cast conversion using C-style cast notation and function-style notation
- user-defined conversion makes it possible to specify conversion from user-defined classes
Memory allocation
- new expression allocates memory dynamically
- delete expression deallocates memory dynamically
Other
- constant expressions can be evaluated at compile time and used in compile-time context (template arguments, array sizes, etc)
-
sizeof
-
alignof
-
typeid
- throw-expression
Primary expressions
The operands of any operator may be other expressions or primary expressions (e.g. in 1 + 2 * 3, the operands of operator+ are the subexpression 2 * 3 and the primary expression 1).
Primary expressions are any of the following:
-
this
- literals (e.g. 2 or "Hello, world")
- identifier expressions, including
- suitably declared unqualified identifiers (e.g. n or cout),
- suitably declared qualified identifiers (e.g. std::string::npos), and
- identifiers to be declared in declarators
(since C++26) |
(since C++11) | |
(since C++17) | |
(since C++20) |
Any expression in parentheses is also classified as a primary expression: this guarantees that the parentheses have higher precedence than any operator. Parentheses preserve value, type, and value category.
Literals
Literals are the tokens of a C++ program that represent constant values embedded in the source code.
- integer literals are decimal, octal, hexadecimal or binary numbers of integer type.
- character literals are individual characters of type
- char or wchar_t
|
(since C++11) |
|
(since C++20) |
- floating-point literals are values of type float, double, or long double
- string literals are sequences of characters of type
- const char[] or const wchar_t[]
|
(since C++11) |
|
(since C++20) |
- boolean literals are values of type bool, that is true and false
|
(since C++11) |
Full-expressions
A constituent expression is defined as follows:
- The constituent expression of an expression is that expression.
- The constituent expressions of a braced-init-list or of a (possibly parenthesized) expression list are the constituent expressions of the elements of the respective list.
- The constituent expressions of a brace-or-equal-initializer of the form
=
initializer-clause are the constituent expressions of the initializer-clause.
int num1 = 0; num1 += 1; // Case 1: the constituent expression of `num += 1` is `num += 1` int arr2[2] = {2, 22} // Case 2: the constituent expressions // of `{2, 22}` are `2` and `22` // Case 3: the constituent expressions of ` = {2, 22}` // are the constituent expressions of `{2, 22}` // (i.e. also `2` and `22`)
The immediate subexpressions of an expression E are
- the constituent expressions of E’s operands,
|
(since C++14) |
|
(since C++11) |
- any function call that E implicitly invokes, or
- if E is a function call or implicitly invokes a function, the constituent expressions of each default argument used in the call.
A subexpression of an expression E is an immediate subexpression of E or a subexpression of an immediate subexpression of E. Note that expressions appearing in the 'function body' of lambda expressions are not subexpressions of the lambda expression.(since C++11)
A full-expression is
(since C++20) |
- a declarator of a simple declaration or a member initializer, including the constituent expressions of the initializer,
- an invocation of a destructor generated at the end of the lifetime of an object other than a temporary object whose lifetime has not been extended, or
- an expression that is not a subexpression of another expression and that is not otherwise part of a full-expression.
If a language construct is defined to produce an implicit call of a function, a use of the language construct is considered to be an expression for the purposes of this definition. Conversions applied to the result of an expression in order to satisfy the requirements of the language construct in which the expression appears are also considered to be part of the full-expression.
For an initializer, performing the initialization of the entity (including evaluating default member initializers of an aggregate)(since C++14) is also considered part of the full-expression.
Potentially-evaluated expressions
An expression is potentially evaluated unless
|
(until C++11) | ||
The following operands are unevaluated operands , they are not evaluated:
An expression is potentially evaluated unless
|
(since C++11) |
Potentially-evaluated expressions are ODR-use.
This section is incomplete Reason: example of unevaluated operands |
Discarded-value expressions
A discarded-value expression is an expression that is used for its side-effects only. The value calculated from such expression is discarded. Such expressions include the full-expression of any expression statement, the left-hand operand of the built-in comma operator, or the operand of a cast-expression that casts to the type void.
Array-to-pointer and function-to-pointer conversions are never applied to the value calculated by a discarded-value expression. The lvalue-to-rvalue conversion is applied if and only if the expression is a volatile-qualified glvalue and has one of the following forms (built-in meaning required, possibly parenthesized):
- id-expression,
- array subscript expression,
- class member access expression,
- indirection,
- pointer-to-member operation,
- conditional expression where both the second and the third operands are one of these expressions,
- comma expression where the right operand is one of these expressions.
In addition, if the lvalue is of volatile-qualified class type, a volatile copy constructor is required to initialize the resulting rvalue temporary.
If the expression is a non-void prvalue (after any lvalue-to-rvalue conversion that might have taken place), temporary materialization occurs. Compilers may issue warnings when an expression other than cast to void discards a value declared |
(since C++17) |
Expression-equivalenceA number of expressions e1, e2, ..., eN are expression-equivalent if all following conditions are satisfied:
e1 is expression-equivalent to e2 if and only if e1 and e2 are expression-equivalent (which means e2 is also expression-equivalent to e1). |
(since C++20) |
Defect reports
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
CWG 1054 | C++98 | assigning a value to a volatile variable might result in an unnecessary read due to the lvalue-to- rvalue conversion applied to the assignment result |
introduce discarded-value expressions and exclude this case from the list of cases that require the conversion |
CWG 1343 | C++98 | sequencing of destructor calls in aggregate initialization was underspecified |
full-expressions in aggregate initialization are well-specified |
CWG 1383 | C++98 | the list of expressions where lvalue-to-rvalue conversion is applied to discarded-value expressions also covered overloaded operators |
only cover operators with built-in meaning |
CWG 1576 | C++11 | lvalue-to-rvalue conversions were not applied to discarded-value volatile xvalue expressions |
apply the conversion in this case |
CWG 2249 | C++98 | identifiers to be declared in declarators were not id-expressions |
they are |
CWG 2431 | C++11 | the invocations of the destructors of temporaries that are bound to references were not full-expressions |
they are |
See also
C documentation for Expressions
|