Files
cppdraft_translate/cppdraft/expr/const.md
2025-10-25 03:02:53 +03:00

1121 lines
53 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[expr.const]
# 7 Expressions [[expr]](./#expr)
## 7.7 Constant expressions [expr.const]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L8242)
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[.](#1.sentence-1)
Expressions that satisfy these requirements,
assuming that [copy elision](class.copy.elision "11.9.6Copy/move elision[class.copy.elision]") is not performed,
are called[*constant expressions*](#def:constant_expression "7.7Constant expressions[expr.const]")[.](#1.sentence-2)
[*Note [1](#note-1)*:
Constant expressions can be evaluated
during translation[.](#1.sentence-3)
— *end note*]
[constant-expression:](#nt:constant-expression "7.7Constant expressions[expr.const]")
[*conditional-expression*](expr.cond#nt:conditional-expression "7.6.16Conditional operator[expr.cond]")
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L8261)
The [*constituent values*](#def:constituent_value "7.7Constant expressions[expr.const]") of an object o are
- [(2.1)](#2.1)
if o has scalar type, the value of o;
- [(2.2)](#2.2)
otherwise, the constituent values of any direct subobjects of o other than inactive union members[.](#2.sentence-1)
The [*constituent references*](#def:constituent_reference "7.7Constant expressions[expr.const]") of an object o are
- [(2.3)](#2.3)
any direct members of o that have reference type, and
- [(2.4)](#2.4)
the constituent references of any direct subobjects of o other than inactive union members[.](#2.sentence-2)
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L8279)
The constituent values and constituent references of
a variable x are defined as follows:
- [(3.1)](#3.1)
If x declares an object,
the constituent values and references of that object are
constituent values and references of x[.](#3.1.sentence-1)
- [(3.2)](#3.2)
If x declares a reference,
that reference is a constituent reference of x[.](#3.2.sentence-1)
For any constituent reference r of a variable x,
if r is bound to a temporary object or subobject thereof
whose lifetime is extended to that of r,
the constituent values and references of that temporary object
are also constituent values and references of x, recursively[.](#3.sentence-2)
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L8297)
An object o is [*constexpr-referenceable*](#def:constexpr-referenceable "7.7Constant expressions[expr.const]") from a point P if
- [(4.1)](#4.1)
o has static storage duration, or
- [(4.2)](#4.2)
o has automatic storage duration, and, letting v denote
* [(4.2.1)](#4.2.1)
the variable corresponding to o's complete object or
* [(4.2.2)](#4.2.2)
the variable to whose lifetime that of o is extended,
the smallest scope enclosing v and the smallest scope enclosing P that are neither
* [(4.2.3)](#4.2.3)
block scopes nor
* [(4.2.4)](#4.2.4)
function parameter scopes associated with
a [*requirement-parameter-list*](expr.prim.req.general#nt:requirement-parameter-list "7.5.8.1General[expr.prim.req.general]")
are the same function parameter scope.
[*Example [1](#example-1)*: struct A {int m; const int& r;};void f() {static int sx; thread_local int tx; // tx is never constexpr-referenceableint ax;
A aa = {1, 2}; static A sa = {3, 4}; // The objects sx, ax, and aa.m, sa.m, and the temporaries to which aa.r and sa.r are bound, are constexpr-referenceable.auto lambda = [] {int ay; // The objects sx, sa.m, and ay (but not ax or aa), and the// temporary to which sa.r is bound, are constexpr-referenceable.};} — *end example*]
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L8343)
An object or reference x is[*constexpr-representable*](#def:constexpr-representable "7.7Constant expressions[expr.const]") at a point P if,
for each constituent value of x that points to or past an object o,
and for each constituent reference of x that refers to an object o,o is constexpr-referenceable from P[.](#5.sentence-1)
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L8350)
A variable v is [*constant-initializable*](#def:constant-initializable "7.7Constant expressions[expr.const]") if
- [(6.1)](#6.1)
the full-expression of its initialization is a constant expression
when interpreted as a [*constant-expression*](#nt:constant-expression "7.7Constant expressions[expr.const]") with all contract assertions
using the ignore evaluation semantic ([[basic.contract.eval]](basic.contract.eval "6.11.2Evaluation")),
[*Note [2](#note-2)*:
Within this evaluation,std::is_constant_evaluated() ([[meta.const.eval]](meta.const.eval "21.3.12Constant evaluation context"))
returns true[.](#6.1.sentence-1)
— *end note*]
[*Note [3](#note-3)*:
The initialization, when evaluated,
can still evaluate contract assertions
with other evaluation semantics,
resulting in a diagnostic or ill-formed program
if a contract violation occurs[.](#6.1.sentence-2)
— *end note*]
- [(6.2)](#6.2)
immediately after the initializing declaration of v,
the object or reference x declared by v is constexpr-representable, and
- [(6.3)](#6.3)
if x has static or thread storage duration,x is constexpr-representable at the nearest point
whose immediate scope is a namespace scope
that follows the initializing declaration of v[.](#6.sentence-1)
[7](#7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L8382)
A constant-initializable variable is [*constant-initialized*](#def:constant-initialized "7.7Constant expressions[expr.const]") if either it has an initializer or
its type is const-default-constructible ([[dcl.init.general]](dcl.init.general "9.5.1General"))[.](#7.sentence-1)
[*Example [2](#example-2)*: void f() {int ax = 0; // ax is constant-initializedthread_local int tx = 0; // tx is constant-initializedstatic int sx; // sx is not constant-initializedstatic int& rss = sx; // rss is constant-initializedstatic int& rst = tx; // rst is not constant-initializedstatic int& rsa = ax; // rsa is not constant-initializedthread_local int& rts = sx; // rts is constant-initializedthread_local int& rtt = tx; // rtt is not constant-initializedthread_local int& rta = ax; // rta is not constant-initializedint& ras = sx; // ras is constant-initializedint& rat = tx; // rat is not constant-initializedint& raa = ax; // raa is constant-initialized} — *end example*]
[8](#8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L8405)
A variable is [*potentially-constant*](#def:potentially-constant "7.7Constant expressions[expr.const]") if
it is constexpr or
it has reference or non-volatile const-qualified integral or enumeration type[.](#8.sentence-1)
[9](#9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L8410)
A constant-initialized potentially-constant variable V is[*usable in constant expressions*](#def:usable_in_constant_expressions "7.7Constant expressions[expr.const]") at a point P ifV's initializing declaration D is reachable from P and
- [(9.1)](#9.1)
V is constexpr,
- [(9.2)](#9.2)
V is not initialized to a TU-local value, or
- [(9.3)](#9.3)
P is in the same translation unit as D[.](#9.sentence-1)
An object or reference is[*potentially usable in constant expressions*](#def:potentially_usable_in_constant_expressions "7.7Constant expressions[expr.const]") at point P if it is
- [(9.4)](#9.4)
the object or reference declared by a variable
that is usable in constant expressions at P,
- [(9.5)](#9.5)
a temporary object of non-volatile const-qualified literal type
whose lifetime is extended ([[class.temporary]](class.temporary "6.8.7Temporary objects"))
to that of a variable that is usable in constant expressions at P,
- [(9.6)](#9.6)
a [template parameter](temp.param "13.2Template parameters[temp.param]") object,
- [(9.7)](#9.7)
a [string literal](lex.string "5.13.5String literals[lex.string]") object,
- [(9.8)](#9.8)
a non-mutable subobject of any of the above, or
- [(9.9)](#9.9)
a reference member of any of the above[.](#9.sentence-2)
An object or reference is [*usable in constant expressions*](#def:usable_in_constant_expressions "7.7Constant expressions[expr.const]") at point P if it is an object or reference
that is potentially usable in constant expressions at P and
is constexpr-representable at P[.](#9.sentence-3)
[*Example [3](#example-3)*: struct A {int* const & r;};void f(int x) {constexpr A a = {&x}; static_assert(a.r == &x); // OK[&] {static_assert(a.r != nullptr); // error: a.r is not usable in constant expressions at this point}();} — *end example*]
[10](#10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L8457)
An expression E is a [*core constant expression*](#def:expression,core_constant "7.7Constant expressions[expr.const]") unless the evaluation of E, following the rules of the abstract
machine ([[intro.execution]](intro.execution "6.10.1Sequential execution")), would evaluate one of the following:
- [(10.1)](#10.1)
this ([[expr.prim.this]](expr.prim.this "7.5.3This")), except
* [(10.1.1)](#10.1.1)
in a constexpr function ([[dcl.constexpr]](dcl.constexpr "9.2.6The constexpr and consteval specifiers"))
that is being evaluated as part of E or
* [(10.1.2)](#10.1.2)
when appearing as the [*postfix-expression*](expr.post.general#nt:postfix-expression "7.6.1.1General[expr.post.general]") of
an implicit or explicit class member access expression ([[expr.ref]](expr.ref "7.6.1.5Class member access"));
- [(10.2)](#10.2)
a control flow that passes through
a declaration of a block variable ([[basic.scope.block]](basic.scope.block "6.4.3Block scope")) with
static ([[basic.stc.static]](basic.stc.static "6.8.6.2Static storage duration")) or
thread ([[basic.stc.thread]](basic.stc.thread "6.8.6.3Thread storage duration")) storage duration,
unless that variable is usable in constant expressions;
[*Example [4](#example-4)*: constexpr char test() {static const int x = 5; static constexpr char c[] = "Hello World"; return *(c + x);}static_assert(' ' == test()); — *end example*]
- [(10.3)](#10.3)
an invocation of a non-constexpr function;[67](#footnote-67 "Overload resolution ([over.match]) is applied as usual.")
- [(10.4)](#10.4)
an invocation of an undefined constexpr function;
- [(10.5)](#10.5)
an invocation of an instantiated constexpr function
that is not constexpr-suitable;
- [(10.6)](#10.6)
an invocation of a virtual function ([[class.virtual]](class.virtual "11.7.3Virtual functions"))
for an object whose dynamic type is constexpr-unknown;
- [(10.7)](#10.7)
an expression that would exceed the implementation-defined
limits (see [[implimits]](implimits "Annex B(informative)Implementation quantities"));
- [(10.8)](#10.8)
an operation that would have undefined or erroneous behavior
as specified in [[intro]](intro "4General principles") through [[cpp]](cpp "15Preprocessing directives");[68](#footnote-68 "This includes, for example, signed integer overflow ([expr.pre]), certain pointer arithmetic ([expr.add]), division by zero ([expr.mul]), or certain shift operations ([expr.shift]).")
- [(10.9)](#10.9)
an [lvalue-to-rvalue conversion](conv.lval "7.3.2Lvalue-to-rvalue conversion[conv.lval]") unless
it is applied to
* [(10.9.1)](#10.9.1)
a glvalue of type cv std::nullptr_t,
* [(10.9.2)](#10.9.2)
a non-volatile glvalue that refers to an object that is
usable in constant expressions, or
* [(10.9.3)](#10.9.3)
a non-volatile glvalue of literal type that refers to a non-volatile object
whose lifetime began within the evaluation of E;
- [(10.10)](#10.10)
an lvalue-to-rvalue conversion
that is applied to a glvalue
that refers to a non-active member of a union or a subobject thereof;
- [(10.11)](#10.11)
an lvalue-to-rvalue conversion that is applied to
an object with an [indeterminate value](basic.indet#def:value,indeterminate "6.8.5Indeterminate and erroneous values[basic.indet]");
- [(10.12)](#10.12)
an invocation of an implicitly-defined copy/move constructor or
copy/move assignment operator
for a union whose active member (if any) is mutable,
unless the lifetime of the union object began within the evaluation of E;
- [(10.13)](#10.13)
in a [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1General[expr.prim.lambda.general]"),
a reference to this or to a variable with
automatic storage duration defined outside that[*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1General[expr.prim.lambda.general]"), where
the reference would be an odr-use ([[basic.def.odr]](basic.def.odr#term.odr.use "6.3One-definition rule"), [[expr.prim.lambda]](expr.prim.lambda "7.5.6Lambda expressions"));
[*Example [5](#example-5)*: void g() {const int n = 0; [=] {constexpr int i = n; // OK, n is not odr-used hereconstexpr int j = *&n; // error: &n would be an odr-use of n};} — *end example*]
[*Note [4](#note-4)*:
If the odr-use occurs in an invocation
of a function call operator of a closure type,
it no longer refers to this or to an enclosing
variable with automatic storage duration
due to the transformation ([[expr.prim.lambda.capture]](expr.prim.lambda.capture "7.5.6.3Captures"))
of the [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1General[expr.prim.id.general]") into
an access of the corresponding data member[.](#10.13.sentence-1)
[*Example [6](#example-6)*: auto monad = [](auto v) { return [=] { return v; }; };auto bind = [](auto m) {return [=](auto fvm) { return fvm(m()); };};
// OK to capture objects with automatic storage duration created during constant expression evaluation.static_assert(bind(monad(2))(monad)() == monad(2)()); — *end example*]
— *end note*]
- [(10.14)](#10.14)
a conversion
from a prvalue P of type “pointer to cv void”
to a type “*cv1* pointer to T”,
where T is not *cv2* void,
unless P is a null pointer value or
points to an object whose type is similar to T;
- [(10.15)](#10.15)
a reinterpret_cast ([[expr.reinterpret.cast]](expr.reinterpret.cast "7.6.1.10Reinterpret cast"));
- [(10.16)](#10.16)
a modification of an object ([[expr.assign]](expr.assign "7.6.19Assignment and compound assignment operators"), [[expr.post.incr]](expr.post.incr "7.6.1.6Increment and decrement"), [[expr.pre.incr]](expr.pre.incr "7.6.2.3Increment and decrement"))
unless it is applied to a non-volatile lvalue of literal type
that refers to a non-volatile object
whose lifetime began within the evaluation of E;
- [(10.17)](#10.17)
an invocation of a destructor ([[class.dtor]](class.dtor "11.4.7Destructors")) or a function call
whose [*postfix-expression*](expr.post.general#nt:postfix-expression "7.6.1.1General[expr.post.general]") names a pseudo-destructor ([[expr.call]](expr.call "7.6.1.3Function call")),
in either case for an object whose lifetime did not begin within the evaluation of E;
- [(10.18)](#10.18)
a [*new-expression*](expr.new#nt:new-expression "7.6.2.8New[expr.new]") ([[expr.new]](expr.new "7.6.2.8New")),
unless either
* [(10.18.1)](#10.18.1)
the selected allocation function is
a replaceable global allocation function ([[new.delete.single]](new.delete.single "17.6.3.2Single-object forms"), [[new.delete.array]](new.delete.array "17.6.3.3Array forms")) and
the allocated storage is deallocated within the evaluation of E, or
* [(10.18.2)](#10.18.2)
the selected allocation function is
a non-allocating form ([[new.delete.placement]](new.delete.placement "17.6.3.4Non-allocating forms"))
with an allocated type T, where
+
[(10.18.2.1)](#10.18.2.1)
the placement argument to the [*new-expression*](expr.new#nt:new-expression "7.6.2.8New[expr.new]") points to
an object whose type is similar to T ([[conv.qual]](conv.qual "7.3.6Qualification conversions")) or,
if T is an array type,
to the first element of an object of a type similar to T, and
+
[(10.18.2.2)](#10.18.2.2)
the placement argument points to storage
whose duration began within the evaluation of E;
- [(10.19)](#10.19)
a [*delete-expression*](expr.delete#nt:delete-expression "7.6.2.9Delete[expr.delete]") ([[expr.delete]](expr.delete "7.6.2.9Delete")),
unless it deallocates a region of storage
allocated within the evaluation of E;
- [(10.20)](#10.20)
a call to an instance ofstd::allocator<T>::allocate ([[allocator.members]](allocator.members "20.2.10.2Members")),
unless the allocated storage is deallocated within the evaluation of E;
- [(10.21)](#10.21)
a call to an instance ofstd::allocator<T>::deallocate ([[allocator.members]](allocator.members "20.2.10.2Members")),
unless it deallocates a region of storage
allocated within the evaluation of E;
- [(10.22)](#10.22)
a construction of an exception object,
unless the exception object and
all of its implicit copies created by invocations ofstd::current_exception or std::rethrow_exception ([[propagation]](propagation "17.9.7Exception propagation"))
are destroyed within the evaluation of E;
- [(10.23)](#10.23)
an [*await-expression*](expr.await#nt:await-expression "7.6.2.4Await[expr.await]") ([[expr.await]](expr.await "7.6.2.4Await"));
- [(10.24)](#10.24)
a [*yield-expression*](expr.yield#nt:yield-expression "7.6.17Yielding a value[expr.yield]") ([[expr.yield]](expr.yield "7.6.17Yielding a value"));
- [(10.25)](#10.25)
a three-way comparison ([[expr.spaceship]](expr.spaceship "7.6.8Three-way comparison operator")),
relational ([[expr.rel]](expr.rel "7.6.9Relational operators")), or equality ([[expr.eq]](expr.eq "7.6.10Equality operators"))
operator where the result is unspecified;
- [(10.26)](#10.26)
a dynamic_cast ([[expr.dynamic.cast]](expr.dynamic.cast "7.6.1.7Dynamic cast")) ortypeid ([[expr.typeid]](expr.typeid "7.6.1.8Type identification")) expression
on a glvalue that refers to an object
whose dynamic type is constexpr-unknown;
- [(10.27)](#10.27)
a dynamic_cast ([[expr.dynamic.cast]](expr.dynamic.cast "7.6.1.7Dynamic cast")) expression,typeid ([[expr.typeid]](expr.typeid "7.6.1.8Type identification")) expression, ornew-expression ([[expr.new]](expr.new "7.6.2.8New"))
that would throw an exception
where no definition of the exception type is reachable;
- [(10.28)](#10.28)
an expression that would produce an injected declaration (see below),
unless E is the corresponding expression of
a [*consteval-block-declaration*](dcl.pre#nt:consteval-block-declaration "9.1Preamble[dcl.pre]") ([[dcl.pre]](dcl.pre "9.1Preamble"));
- [(10.29)](#10.29)
an [*asm-declaration*](dcl.asm#nt:asm-declaration "9.11The asm declaration[dcl.asm]") ([[dcl.asm]](dcl.asm "9.11The asm declaration"));
- [(10.30)](#10.30)
an invocation of the va_arg macro ([[cstdarg.syn]](cstdarg.syn "17.14.2Header <cstdarg> synopsis"));
- [(10.31)](#10.31)
a non-constant library call ([[defns.nonconst.libcall]](defns.nonconst.libcall "3.35non-constant library call"));
or
- [(10.32)](#10.32)
a goto statement ([[stmt.goto]](stmt.goto "8.8.6The goto statement"))[.](#10.sentence-1)
[*Note [5](#note-5)*:
A goto statement introduced by equivalence ([[stmt]](stmt "8Statements"))
is not in scope[.](#10.32.sentence-2)
For example, a while statement ([[stmt.while]](stmt.while "8.6.2The while statement"))
can be executed during constant evaluation[.](#10.32.sentence-3)
— *end note*]
[11](#11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L8710)
It isimplementation-defined
whether E is a core constant expression
if E satisfies the constraints of a core constant expression, but
evaluation of E has runtime-undefined behavior[.](#11.sentence-1)
[12](#12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L8717)
It is unspecified whether E is a core constant expression
if E satisfies the constraints of a core constant expression, but
evaluation of E would evaluate
- [(12.1)](#12.1)
an operation that has undefined behavior
as specified in [[library]](library "16Library introduction") through [[exec]](exec "33Execution control library") or
- [(12.2)](#12.2)
an invocation of the va_start macro ([[cstdarg.syn]](cstdarg.syn "17.14.2Header <cstdarg> synopsis"))[.](#12.sentence-1)
[13](#13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L8729)
[*Example [7](#example-7)*: int x; // not constantstruct A {constexpr A(bool b) : m(b?42:x) { }int m;};constexpr int v = A(true).m; // OK, constructor call initializes m with the value 42constexpr int w = A(false).m; // error: initializer for m is x, which is non-constantconstexpr int f1(int k) {constexpr int x = k; // error: x is not initialized by a constant expression// because lifetime of k began outside the initializer of xreturn x;}constexpr int f2(int k) {int x = k; // OK, not required to be a constant expression// because x is not constexprreturn x;}constexpr int incr(int &n) {return ++n;}constexpr int g(int k) {constexpr int x = incr(k); // error: incr(k) is not a core constant expression// because lifetime of k began outside the expression incr(k)return x;}constexpr int h(int k) {int x = incr(k); // OK, incr(k) is not required to be a core constant expressionreturn x;}constexpr int y = h(1); // OK, initializes y with the value 2// h(1) is a core constant expression because// the lifetime of k begins inside h(1) — *end example*]
[14](#14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L8770)
For the purposes of determining
whether an expression E is a core constant expression,
the evaluation of the body of a member function of std::allocator<T> as defined in [[allocator.members]](allocator.members "20.2.10.2Members"), where T is a literal type,
is ignored[.](#14.sentence-1)
[15](#15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L8777)
For the purposes of determining whether E is a core constant expression,
the evaluation of a call to
a trivial copy/move constructor or copy/move assignment operator of a union
is considered to copy/move the active member of the union, if any[.](#15.sentence-1)
[*Note [6](#note-6)*:
The copy/move of the active member is trivial[.](#15.sentence-2)
— *end note*]
[16](#16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L8786)
For the purposes of determining whether E is a core constant expression,
the evaluation of an [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1General[expr.prim.id.general]") that names a structured binding v ([[dcl.struct.bind]](dcl.struct.bind "9.7Structured binding declarations")) has the
following semantics:
- [(16.1)](#16.1)
If v is an lvalue referring to the object bound to an invented reference r,
the behavior is as if r were nominated[.](#16.1.sentence-1)
- [(16.2)](#16.2)
Otherwise, if v names an array element or class member,
the behavior is that of
evaluating e[i] or e.m, respectively,
where e is the name of the variable
initialized from the initializer of the structured binding declaration, andi is the index of the element referred to by v orm is the name of the member referred to by v, respectively[.](#16.2.sentence-1)
[*Example [8](#example-8)*: #include <tuple>struct S {mutable int m; constexpr S(int m): m(m) {}virtual int g() const;};void f(std::tuple<S&> t) {auto [r] = t; static_assert(r.g() >= 0); // error: dynamic type is constexpr-unknownconstexpr auto [m] = S(1); static_assert(m == 1); // error: lvalue-to-rvalue conversion on mutable// subobject e.m, where e is a constexpr object of type Susing A = int[2]; constexpr auto [v0, v1] = A{2, 3}; static_assert(v0 + v1 == 5); // OK, equivalent to e[0] + e[1] where e is a constexpr array} — *end example*]
[17](#17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L8825)
During the evaluation of an expression E as a core constant expression,
all [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1General[expr.prim.id.general]")*s*, [*splice-expression*](expr.prim.splice#nt:splice-expression "7.5.9Expression splicing[expr.prim.splice]")*s*, and
uses of *this that refer to an object or reference
whose lifetime did not begin with the evaluation of E are treated as referring to a specific instance of that object or reference
whose lifetime and that of all subobjects (including all union members)
includes the entire constant evaluation[.](#17.sentence-1)
For such an object that is not usable in constant expressions,
the dynamic type of the object is [*constexpr-unknown*](#def:constexpr-unknown "7.7Constant expressions[expr.const]")[.](#17.sentence-2)
For such a reference that is not usable in constant expressions,
the reference is treated as binding to
an unspecified object of the referenced type
whose lifetime and that of all subobjects includes
the entire constant evaluation and whose dynamic type is constexpr-unknown[.](#17.sentence-3)
[*Example [9](#example-9)*: template <typename T, size_t N>constexpr size_t array_size(T (&)[N]) {return N;}void use_array(int const (&gold_medal_mel)[2]) {constexpr auto gold = array_size(gold_medal_mel); // OK}constexpr auto olympic_mile() {const int ledecky = 1500; return []{ return ledecky; };}static_assert(olympic_mile()() == 1500); // OKstruct Swim {constexpr int phelps() { return 28; }virtual constexpr int lochte() { return 12; }int coughlin = 12;};
constexpr int how_many(Swim& swam) { Swim* p = &swam; return (p + 1 - 1)->phelps();}void splash(Swim& swam) {static_assert(swam.phelps() == 28); // OKstatic_assert((&swam)->phelps() == 28); // OK Swim* pswam = &swam; static_assert(pswam->phelps() == 28); // error: lvalue-to-rvalue conversion on a pointer// not usable in constant expressionsstatic_assert(how_many(swam) == 28); // OKstatic_assert(Swim().lochte() == 12); // OKstatic_assert(swam.lochte() == 12); // error: invoking virtual function on reference// with constexpr-unknown dynamic typestatic_assert(swam.coughlin == 12); // error: lvalue-to-rvalue conversion on an object// not usable in constant expressions}extern Swim dc;extern Swim& trident;
constexpr auto& sandeno = typeid(dc); // OK, can only be typeid(Swim)constexpr auto& gallagher = typeid(trident); // error: constexpr-unknown dynamic type — *end example*]
[18](#18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L8895)
An object a is said to have [*constant destruction*](#def:destruction,constant "7.7Constant expressions[expr.const]") if
- [(18.1)](#18.1)
it is not of class type nor (possibly multidimensional) array thereof, or
- [(18.2)](#18.2)
it is of class type or (possibly multidimensional) array thereof,
that class type has a constexpr destructor ([[dcl.constexpr]](dcl.constexpr "9.2.6The constexpr and consteval specifiers")), and
for a hypothetical expression E whose only effect is to destroy a, E would be a core constant expression
if the lifetime of a and its non-mutable subobjects
(but not its mutable subobjects) were considered to start within E[.](#18.sentence-1)
[19](#19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L8910)
An [*integral constant expression*](#def:expression,integral_constant "7.7Constant expressions[expr.const]") is an expression of integral or
unscoped enumeration type, implicitly converted to a prvalue, where the converted expression is a core constant expression[.](#19.sentence-1)
[*Note [7](#note-7)*:
Such expressions can be
used as bit-field lengths ([[class.bit]](class.bit "11.4.10Bit-fields")), as enumerator
initializers if the underlying type is not fixed ([[dcl.enum]](dcl.enum "9.8.1Enumeration declarations")),
and as [alignments](dcl.align "9.13.2Alignment specifier[dcl.align]")[.](#19.sentence-2)
— *end note*]
[20](#20)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L8921)
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]](conv "7.3Standard conversions")) to an integral or unscoped
enumeration type
and the selected conversion function shall be constexpr[.](#20.sentence-1)
[*Example [10](#example-10)*: 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; // error: ambiguous conversionstruct B { int n : a; }; // error: ambiguous conversion — *end example*]
[21](#21)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L8942)
A [*converted constant expression*](#def:expression,converted_constant "7.7Constant expressions[expr.const]") of 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
- [(21.1)](#21.1)
user-defined conversions,
- [(21.2)](#21.2)
lvalue-to-rvalue conversions ([[conv.lval]](conv.lval "7.3.2Lvalue-to-rvalue conversion")),
- [(21.3)](#21.3)
array-to-pointer conversions ([[conv.array]](conv.array "7.3.3Array-to-pointer conversion")),
- [(21.4)](#21.4)
function-to-pointer conversions ([[conv.func]](conv.func "7.3.4Function-to-pointer conversion")),
- [(21.5)](#21.5)
qualification conversions ([[conv.qual]](conv.qual "7.3.6Qualification conversions")),
- [(21.6)](#21.6)
integral promotions ([[conv.prom]](conv.prom "7.3.7Integral promotions")),
- [(21.7)](#21.7)
integral conversions ([[conv.integral]](conv.integral "7.3.9Integral conversions")) other than narrowing conversions ([[dcl.init.list]](dcl.init.list "9.5.5List-initialization")),
- [(21.8)](#21.8)
floating-point promotions ([[conv.fpprom]](conv.fpprom "7.3.8Floating-point promotion")),
- [(21.9)](#21.9)
floating-point conversions ([[conv.double]](conv.double "7.3.10Floating-point conversions")) where
the source value can be represented exactly in the destination type,
- [(21.10)](#21.10)
null pointer conversions ([[conv.ptr]](conv.ptr "7.3.12Pointer conversions")) from std::nullptr_t,
- [(21.11)](#21.11)
null member pointer conversions ([[conv.mem]](conv.mem "7.3.13Pointer-to-member conversions")) from std::nullptr_t, and
- [(21.12)](#21.12)
function pointer conversions ([[conv.fctptr]](conv.fctptr "7.3.14Function pointer conversions")),
and where the reference binding (if any) binds directly[.](#21.sentence-1)
[*Note [8](#note-8)*:
Such expressions can be used in new expressions ([[expr.new]](expr.new "7.6.2.8New")), as case expressions ([[stmt.switch]](stmt.switch "8.5.3The switch statement")),
as enumerator initializers if the underlying type is
fixed ([[dcl.enum]](dcl.enum "9.8.1Enumeration declarations")), as array bounds ([[dcl.array]](dcl.array "9.3.4.5Arrays")),
as constant template arguments ([[temp.arg]](temp.arg "13.4Template arguments")),
and as the constant expression of a [*splice-specifier*](basic.splice#nt:splice-specifier "6.6Splice specifiers[basic.splice]") ([[basic.splice]](basic.splice "6.6Splice specifiers"))[.](#21.sentence-2)
— *end note*]
A [*contextually converted constant expression of type bool*](#def:contextually_converted_constant_expression_of_type_bool) is
an expression, contextually converted to bool ([[conv]](conv "7.3Standard conversions")),
where the converted expression is a constant expression and
the conversion sequence contains only the conversions above[.](#21.sentence-3)
[22](#22)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L8979)
A [*constant expression*](#def:expression,constant "7.7Constant expressions[expr.const]") is either
- [(22.1)](#22.1)
a glvalue core constant expression E for which
* [(22.1.1)](#22.1.1)
E refers to a non-immediate function,
* [(22.1.2)](#22.1.2)
E designates an object o, and
if the complete object of o is of consteval-only type then so is E,
[*Example [11](#example-11)*: struct Base { };struct Derived : Base { std::meta::info r; };
consteval const Base& fn(const Derived& derived) { return derived; }constexpr Derived obj{.r=^^::}; // OKconstexpr const Derived& d = obj; // OKconstexpr const Base& b = fn(obj); // error: not a constant expression because Derived// is a consteval-only type but Base is not. — *end example*]
or
- [(22.2)](#22.2)
a prvalue core constant expression whose result object ([[basic.lval]](basic.lval "7.2.1Value category"))
satisfies the following constraints:
* [(22.2.1)](#22.2.1)
each constituent reference refers to an object or a non-immediate function,
* [(22.2.2)](#22.2.2)
no constituent value of scalar type is an indeterminate or erroneous value ([[basic.indet]](basic.indet "6.8.5Indeterminate and erroneous values")),
* [(22.2.3)](#22.2.3)
no constituent value of pointer type is a pointer to an immediate function or
an invalid pointer value ([[basic.compound]](basic.compound "6.9.4Compound types")),
* [(22.2.4)](#22.2.4)
no constituent value of pointer-to-member type designates an immediate function, and
* [(22.2.5)](#22.2.5)
unless the value is of consteval-only type,
+
[(22.2.5.1)](#22.2.5.1)
no constituent value of pointer-to-member type points to
a direct member of a consteval-only class type,
+
[(22.2.5.2)](#22.2.5.2)
no constituent value of pointer type points to or past an object
whose complete object is of consteval-only type, and
+
[(22.2.5.3)](#22.2.5.3)
no constituent reference refers to an object
whose complete object is of consteval-only type[.](#22.sentence-1)
[*Note [9](#note-9)*:
A glvalue core constant expression
that either refers to or points to an unspecified object
is not a constant expression[.](#22.sentence-2)
— *end note*]
[*Example [12](#example-12)*: consteval int f() { return 42; }consteval auto g() { return f; }consteval int h(int (*p)() = g()) { return p(); }constexpr int r = h(); // OKconstexpr auto e = g(); // error: a pointer to an immediate function is// not a permitted result of a constant expressionstruct S {int x; constexpr S() {}};int i() {constexpr S s; // error: s.x has erroneous value} — *end example*]
[23](#23)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L9057)
*Recommended practice*: Implementations should provide consistent results of floating-point evaluations,
irrespective of whether the evaluation is performed
during translation or during program execution[.](#23.sentence-1)
[*Note [10](#note-10)*:
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[.](#23.sentence-2)
[*Example [13](#example-13)*: bool f() {char array[1 + int(1 + 0.2 - 0.1 - 0.1)]; // Must be evaluated during translationint size = 1 + int(1 + 0.2 - 0.1 - 0.1); // May be evaluated at runtimereturn sizeof(array) == size;}
It is unspecified whether the value of f() will be true or false[.](#23.sentence-3)
— *end example*]
— *end note*]
[24](#24)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L9080)
An expression or conversion is in an [*immediate function context*](#def:immediate_function_context "7.7Constant expressions[expr.const]") if it is potentially evaluated and either:
- [(24.1)](#24.1)
its innermost enclosing non-block scope is
a function parameter scope of an immediate function,
- [(24.2)](#24.2)
it is a subexpression of a manifestly constant-evaluated expression
or conversion, or
- [(24.3)](#24.3)
its enclosing statement is enclosed ([[stmt.pre]](stmt.pre "8.1Preamble")) by
the [*compound-statement*](stmt.block#nt:compound-statement "8.4Compound statement or block[stmt.block]") of a consteval if statement ([[stmt.if]](stmt.if "8.5.2The if statement"))[.](#24.sentence-1)
An invocation is an [*immediate invocation*](#def:immediate_invocation "7.7Constant expressions[expr.const]") if it is a potentially-evaluated explicit or implicit invocation of
an immediate function and
is not in an immediate function context[.](#24.sentence-2)
An aggregate initialization is an immediate invocation
if it evaluates a default member initializer
that has a subexpression that is an immediate-escalating expression[.](#24.sentence-3)
[25](#25)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L9102)
A potentially-evaluated expression or conversion is [*immediate-escalating*](#def:immediate-escalating "7.7Constant expressions[expr.const]") if it is neither initially in an immediate function context
nor a subexpression of an immediate invocation, and
- [(25.1)](#25.1)
it is an [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1General[expr.prim.id.general]") or [*splice-expression*](expr.prim.splice#nt:splice-expression "7.5.9Expression splicing[expr.prim.splice]") that designates an immediate function,
- [(25.2)](#25.2)
it is an immediate invocation that is not a constant expression, or
- [(25.3)](#25.3)
it is of consteval-only type ([[basic.types.general]](basic.types.general "6.9.1General"))[.](#25.sentence-1)
[26](#26)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L9120)
An [*immediate-escalating*](#def:function,immediate-escalating "7.7Constant expressions[expr.const]") function is
- [(26.1)](#26.1)
the call operator of a lambda that is not declared
with the consteval specifier,
- [(26.2)](#26.2)
a defaulted special member function
that is not declared with the consteval specifier, or
- [(26.3)](#26.3)
a function that results from the instantiation
of a templated entity defined with the constexpr specifier[.](#26.sentence-1)
An immediate-escalating expression shall appear only
in an immediate-escalating function[.](#26.sentence-2)
[27](#27)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L9137)
An [*immediate function*](#def:function,immediate "7.7Constant expressions[expr.const]") is a function or constructor that is either
- [(27.1)](#27.1)
declared with the consteval specifier, or
- [(27.2)](#27.2)
an immediate-escalating function *F* whose function body contains either
* [(27.2.1)](#27.2.1)
an immediate-escalating expression or
* [(27.2.2)](#27.2.2)
a definition of a non-constexpr variable with consteval-only type
whose innermost enclosing non-block scope
is *F*'s function parameter scope. [*Note [11](#note-11)*:
Default member initializers used to initialize
a base or member subobject ([[class.base.init]](class.base.init "11.9.3Initializing bases and members"))
are considered to be part of the function body ([[dcl.fct.def.general]](dcl.fct.def.general "9.6.1General"))[.](#27.2.sentence-2)
— *end note*]
[*Example [14](#example-14)*: consteval int id(int i) { return i; }constexpr char id(char c) { return c; }template<class T>constexpr int f(T t) {return t + id(t);}auto a = &f<char>; // OK, f<char> is not an immediate functionauto b = &f<int>; // error: f<int> is an immediate functionstatic_assert(f(3) == 6); // OKtemplate<class T>constexpr int g(T t) { // g<int> is not an immediate functionreturn t + id(42); // because id(42) is already a constant}template<class T, class F>constexpr bool is_not(T t, F f) {return not f(t);}consteval bool is_even(int i) { return i % 2 == 0; }static_assert(is_not(5, is_even)); // OKint x = 0;
template<class T>constexpr T h(T t = id(x)) { // h<int> is not an immediate function// id(x) is not evaluated when parsing the default argument ([[dcl.fct.default]](dcl.fct.default "9.3.4.7Default arguments"), [[temp.inst]](temp.inst "13.9.2Implicit instantiation"))return t;}template<class T>constexpr T hh() { // hh<int> is an immediate function because of the invocationreturn h<T>(); // of the immediate function id in the default argument of h<int>}int i = hh<int>(); // error: hh<int>() is an immediate-escalating expression// outside of an immediate-escalating functionstruct A {int x; int y = id(x);};
template<class T>constexpr int k(int) { // k<int> is not an immediate function because A(42) is areturn A(42).y; // constant expression and thus not immediate-escalating}constexpr int l(int c) pre(c >= 2) {return (c % 2 == 0) ? c / 0 : c;}const int i0 = l(0); // dynamic initialization; contract violation or undefined behaviorconst int i1 = l(1); // static initialization; value of 1 or contract violation at compile timeconst int i2 = l(2); // dynamic initialization; undefined behaviorconst int i3 = l(3); // static initialization; value of 3 — *end example*]
[28](#28)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L9223)
An expression or conversion is [*manifestly constant-evaluated*](#def:manifestly_constant-evaluated "7.7Constant expressions[expr.const]") if it is:
- [(28.1)](#28.1)
a [*constant-expression*](#nt:constant-expression "7.7Constant expressions[expr.const]"), or
- [(28.2)](#28.2)
the condition of a constexpr if statement ([[stmt.if]](stmt.if "8.5.2The if statement")), or
- [(28.3)](#28.3)
an immediate invocation, or
- [(28.4)](#28.4)
the result of substitution into an atomic constraint expression
to determine whether it is satisfied ([[temp.constr.atomic]](temp.constr.atomic "13.5.2.3Atomic constraints")), or
- [(28.5)](#28.5)
the initializer of a variable
that is usable in constant expressions or
has constant initialization ([[basic.start.static]](basic.start.static "6.10.3.2Static initialization"))[.](#28.sentence-1)[69](#footnote-69 "Testing this condition can involve a trial evaluation of its initializer, with evaluations of contract assertions using the ignore evaluation semantic ([basic.contract.eval]), as described above.")
[*Example [15](#example-15)*: template<bool> struct X {};
X<std::is_constant_evaluated()> x; // type X<true>int y;const int a = std::is_constant_evaluated() ? y : 1; // dynamic initialization to 1double z[a]; // error: a is not usable// in constant expressionsconst int b = std::is_constant_evaluated() ? 2 : y; // static initialization to 2int c = y + (std::is_constant_evaluated() ? 2 : y); // dynamic initialization to y+yconstexpr int f() {const int n = std::is_constant_evaluated() ? 13 : 17; // n is 13int m = std::is_constant_evaluated() ? 13 : 17; // m can be 13 or 17 (see below)char arr[n] = {}; // char[13]return m + sizeof(arr);}int p = f(); // m is 13; initialized to 26int q = p + f(); // m is 17 for this call; initialized to 56 — *end example*]
[*Note [12](#note-12)*:
Except for a [*static_assert-message*](dcl.pre#nt:static_assert-message "9.1Preamble[dcl.pre]"),
a manifestly constant-evaluated expression
is evaluated even in an unevaluated operand ([[expr.context]](expr.context#term.unevaluated.operand "7.2.3Context dependence"))[.](#28.sentence-2)
— *end note*]
[29](#29)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L9270)
The evaluation of an expression can introduce
one or more [*injected declarations*](#def:declaration,injected "7.7Constant expressions[expr.const]")[.](#29.sentence-1)
The evaluation is said to [*produce*](#def:produce "7.7Constant expressions[expr.const]") the declarations[.](#29.sentence-2)
[*Note [13](#note-13)*:
An invocation of
the library function template std::meta::define_aggregate produces an injected declaration ([[meta.reflection.define.aggregate]](meta.reflection.define.aggregate "21.4.16Reflection class definition generation"))[.](#29.sentence-3)
— *end note*]
Each such declaration has
- [(29.1)](#29.1)
an associated [*synthesized point*](#def:point,synthesized "7.7Constant expressions[expr.const]"),
which follows the last non-synthesized program point
in the translation unit containing that declaration, and
- [(29.2)](#29.2)
an associated [*characteristic sequence*](#def:sequence,characteristic "7.7Constant expressions[expr.const]") of values[.](#29.sentence-4)
[*Note [14](#note-14)*:
Special rules concerning reachability
apply to synthesized points ([[module.reach]](module.reach "10.7Reachability"))[.](#29.sentence-5)
— *end note*]
[*Note [15](#note-15)*:
The program is ill-formed
if injected declarations with different characteristic sequences
define the same entity in different translation units ([[basic.def.odr]](basic.def.odr "6.3One-definition rule"))[.](#29.sentence-6)
— *end note*]
[30](#30)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L9298)
A member of an entity defined by an injected declaration
shall not have a name reserved to the implementation ([[lex.name]](lex.name "5.11Identifiers"));
no diagnostic is required[.](#30.sentence-1)
[31](#31)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L9303)
Let C be a [*consteval-block-declaration*](dcl.pre#nt:consteval-block-declaration "9.1Preamble[dcl.pre]"),
the evaluation of whose corresponding expression
produces an injected declaration for an entity E[.](#31.sentence-1)
The program is ill-formed if either
- [(31.1)](#31.1)
C is enclosed by a scope associated with E or
- [(31.2)](#31.2)
letting P be a point whose immediate scope is that to which E belongs,
there is a function parameter scope or class scope
that encloses exactly one of C or P[.](#31.sentence-2)
[*Example [16](#example-16)*: struct S0 {consteval { std::meta::define_aggregate(^^S0, {}); // error: scope associated with S0 encloses the consteval block}};
struct S1;consteval { std::meta::define_aggregate(^^S1, {}); } // OKtemplate <std::meta::info R> consteval void tfn1() { std::meta::define_aggregate(R, {});}struct S2;consteval { tfn1<^^S2>(); } // OKtemplate <std::meta::info R> consteval void tfn2() {consteval { std::meta::define_aggregate(R, {}); }}struct S3;consteval { tfn2<^^S3>(); }// error: function parameter scope of tfn2<^^S3> intervenes between the declaration of S3// and the consteval block that produces the injected declarationtemplate <typename> struct TCls {struct S4; static void sfn() requires ([] {consteval { std::meta::define_aggregate(^^S4, {}); }return true; }()) { }};
consteval { TCls<void>::sfn(); } // error: TCls<void>::S4 is not enclosed by [*requires-clause*](temp.pre#nt:requires-clause "13.1Preamble[temp.pre]") lambdastruct S5;struct Cls {consteval { std::meta::define_aggregate(^^S5, {}); } // error: S5 is not enclosed by class Cls};
struct S6;consteval { // #1struct S7; // local class std::meta::define_aggregate(^^S7, {}); // error: consteval block #1 does not enclose itself,// but encloses S7consteval { // #2 std::meta::define_aggregate(^^S6, {}); // error: consteval block #1 encloses// consteval block #2 but not S6 std::meta::define_aggregate(^^S7, {}); // OK, consteval block #1 encloses both #2 and S7}} — *end example*]
[32](#32)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L9375)
The [*evaluation context*](#def:evaluation_context "7.7Constant expressions[expr.const]") is a set of program points
that determines the behavior of certain functions
used for reflection ([[meta.reflection]](meta.reflection "21.4Reflection"))[.](#32.sentence-1)
During the evaluation V of an expression E as a core constant expression,
the evaluation context of an evaluation X ([[intro.execution]](intro.execution "6.10.1Sequential execution"))
consists of the following points:
- [(32.1)](#32.1)
The program point EVAL-PT(L),
where L is the point at which E appears, and
where EVAL-PT(P), for a point P,
is a point R determined as follows:
* [(32.1.1)](#32.1.1)
If a potentially-evaluated subexpression ([[intro.execution]](intro.execution "6.10.1Sequential execution")) of
a default member initializer I appears at P, and
a (possibly aggregate) initialization during V is using I,
then R is EVAL-PT(Q) where Q is the point at which that initialization appears[.](#32.1.1.sentence-1)
* [(32.1.2)](#32.1.2)
Otherwise, if a potentially-evaluated subexpression of
a default argument ([[dcl.fct.default]](dcl.fct.default "9.3.4.7Default arguments")) appears at P, and
an invocation of a function ([[expr.call]](expr.call "7.6.1.3Function call")) during V is using that default argument,
then R is EVAL-PT(Q) where Q is the point at which that invocation appears[.](#32.1.2.sentence-1)
* [(32.1.3)](#32.1.3)
Otherwise, R is P[.](#32.1.3.sentence-1)
- [(32.2)](#32.2)
Each synthesized point corresponding to an injected declaration produced by
any evaluation sequenced before X ([[intro.execution]](intro.execution "6.10.1Sequential execution"))[.](#32.2.sentence-1)
[33](#33)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/expressions.tex#L9410)
An expression or conversion is [*potentially constant evaluated*](#def:potentially_constant_evaluated "7.7Constant expressions[expr.const]") if it is:
- [(33.1)](#33.1)
a manifestly constant-evaluated expression,
- [(33.2)](#33.2)
a [potentially-evaluated](basic.def.odr#def:potentially_evaluated "6.3One-definition rule[basic.def.odr]") expression,
- [(33.3)](#33.3)
an immediate subexpression of a [*braced-init-list*](dcl.init.general#nt:braced-init-list "9.5.1General[dcl.init.general]"),[70](#footnote-70 "In some cases, constant evaluation is needed to determine whether a narrowing conversion is performed ([dcl.init.list]).")
- [(33.4)](#33.4)
an expression of the form & [*cast-expression*](expr.cast#nt:cast-expression "7.6.3Explicit type conversion (cast notation)[expr.cast]") that occurs within a templated entity,[71](#footnote-71 "In some cases, constant evaluation is needed to determine whether such an expression is value-dependent ([temp.dep.constexpr]).") or
- [(33.5)](#33.5)
a potentially-evaluated subexpression ([[intro.execution]](intro.execution "6.10.1Sequential execution")) of one of the above[.](#33.sentence-1)
A function or variable is[*needed for constant evaluation*](#def:needed_for_constant_evaluation "7.7Constant expressions[expr.const]") if it is:
- [(33.6)](#33.6)
a constexpr function that[is named by](basic.def.odr#def:function,named_by_expression_or_conversion "6.3One-definition rule[basic.def.odr]") an expression
that is potentially constant evaluated, or
- [(33.7)](#33.7)
a potentially-constant variable named by a potentially constant evaluated expression[.](#33.sentence-2)
[67)](#footnote-67)[67)](#footnoteref-67)
Overload resolution ([[over.match]](over.match "12.2Overload resolution"))
is applied as usual[.](#footnote-67.sentence-1)
[68)](#footnote-68)[68)](#footnoteref-68)
This includes,
for example, signed integer overflow ([[expr.pre]](expr.pre "7.1Preamble")), certain
pointer arithmetic ([[expr.add]](expr.add "7.6.6Additive operators")), division by
zero ([[expr.mul]](expr.mul "7.6.5Multiplicative operators")), or certain shift operations ([[expr.shift]](expr.shift "7.6.7Shift operators"))[.](#footnote-68.sentence-1)
[69)](#footnote-69)[69)](#footnoteref-69)
Testing this condition
can involve a trial evaluation of its initializer,
with evaluations of contract assertions
using the ignore evaluation semantic ([[basic.contract.eval]](basic.contract.eval "6.11.2Evaluation")),
as described above[.](#footnote-69.sentence-1)
[70)](#footnote-70)[70)](#footnoteref-70)
In some cases, constant evaluation is needed to determine whether a narrowing conversion is performed ([[dcl.init.list]](dcl.init.list "9.5.5List-initialization"))[.](#footnote-70.sentence-1)
[71)](#footnote-71)[71)](#footnoteref-71)
In some cases, constant evaluation is needed to determine whether such an expression is value-dependent ([[temp.dep.constexpr]](temp.dep.constexpr "13.8.3.4Value-dependent expressions"))[.](#footnote-71.sentence-1)