[expr.const] (original) (raw)

7 Expressions [expr]

7.7 Constant expressions [expr.const]

Certain contexts require expressions that satisfy additional requirements as detailed in this subclause; other contexts have different semantics depending on whether or not an expression satisfies these requirements.

Expressions that satisfy these requirements, assuming that copy elision is not performed, are calledconstant expressions.

[Note 1:

Constant expressions can be evaluated during translation.

— _end note_]

A variable or temporary object o is constant-initialized if

A variable is potentially-constant if it is constexpr or it has reference or const-qualified integral or enumeration type.

A constant-initialized potentially-constant variable V isusable in constant expressions at a point P ifV's initializing declaration D is reachable from P and

An object or reference is usable in constant expressions if it is

An expression E is a core constant expressionunless the evaluation of E, following the rules of the abstract machine ([intro.execution]), would evaluate one of the following:

If E satisfies the constraints of a core constant expression, but evaluation of E would evaluate an operation that has undefined behavior as specified in [library] through [thread], or an invocation of the va_­start macro ([cstdarg.syn]), it is unspecified whether E is a core constant expression.

[Example 3: int x; struct A { constexpr A(bool b) : m(b?42:x) { } int m;};constexpr int v = A(true).m; constexpr int w = A(false).m; constexpr int f1(int k) { constexpr int x = k; return x;} constexpr int f2(int k) { int x = k; return x;} constexpr int incr(int &n) { return ++n;} constexpr int g(int k) { constexpr int x = incr(k); return x;} constexpr int h(int k) { int x = incr(k); return x;} constexpr int y = h(1); — _end example_]

For the purposes of determining whether an expression E is a core constant expression, the evaluation of a call to a member function of std​::​allocator<T>as defined in [allocator.members], where T is a literal type, does not disqualify E from being a core constant expression, even if the actual evaluation of such a call would otherwise fail the requirements for a core constant expression.

Similarly, the evaluation of a call tostd​::​destroy_­at,std​::​ranges​::​destroy_­at,std​::​construct_­at, orstd​::​ranges​::​construct_­atdoes not disqualify Efrom being a core constant expression unless:

An object a is said to have constant destruction if:

An integral constant expressionis an expression of integral or unscoped enumeration type, implicitly converted to a prvalue, where the converted expression is a core constant expression.

[Note 4:

Such expressions can be used as bit-field lengths ([class.bit]), as enumerator initializers if the underlying type is not fixed ([dcl.enum]), and as alignments.

— _end note_]

If an expression of literal class type is used in a context where an integral constant expression is required, then that expression is contextually implicitly converted ([conv]) to an integral or unscoped enumeration type and the selected conversion function shall be constexpr.

[Example 4: struct A { constexpr A(int i) : val(i) { } constexpr operator int() const { return val; } constexpr operator long() const { return 42; } private: int val;};constexpr A a = alignof(int);alignas(a) int n; struct B { int n : a; }; — _end example_]

A converted constant expressionof type T is an expression, implicitly converted to type T, where the converted expression is a constant expression and the implicit conversion sequence contains only

and where the reference binding (if any) binds directly.

A contextually converted constant expression of type bool is an expression, contextually converted to bool, where the converted expression is a constant expression and the conversion sequence contains only the conversions above.

A constant expression is either a glvalue core constant expression that refers to an entity that is a permitted result of a constant expression (as defined below), or a prvalue core constant expression whose value satisfies the following constraints:

An entity is apermitted result of a constant expressionif it is an object with static storage duration that either is not a temporary object or is a temporary object whose value satisfies the above constraints, or if it is a non-immediate function.

[Example 5: consteval int f() { return 42; } consteval auto g() { return f; } consteval int h(int (*p)() = g()) { return p(); } constexpr int r = h(); constexpr auto e = g(); — _end example_]

Recommended practice: Implementations should provide consistent results of floating-point evaluations, irrespective of whether the evaluation is performed during translation or during program execution.

[Note 6:

Since this document imposes no restrictions on the accuracy of floating-point operations, it is unspecified whether the evaluation of a floating-point expression during translation yields the same result as the evaluation of the same expression (or the same operations on the same values) during program execution.

[Example 6: bool f() { char array[1 + int(1 + 0.2 - 0.1 - 0.1)]; int size = 1 + int(1 + 0.2 - 0.1 - 0.1); return sizeof(array) == size;}

It is unspecified whether the value of f() will be true or false.

— _end example_]

— _end note_]

An expression or conversion is in an immediate function contextif it is potentially evaluated and its innermost non-block scope is a function parameter scope of an immediate function.

An expression or conversion is an immediate invocationif it is a potentially-evaluated explicit or implicit invocation of an immediate function and is not in an immediate function context.

An immediate invocation shall be a constant expression.

An expression or conversion is manifestly constant-evaluatedif it is:

[Note 7:

A manifestly constant-evaluated expression is evaluated even in an unevaluated operand.

— _end note_]

An expression or conversion is potentially constant evaluatedif it is:

A function or variable isneeded for constant evaluationif it is: