Defines an
that can be evaluated at compile time.
Such expressions can be used as non-type template arguments, array sizes, and in other contexts that require constant expressions, e.g.
intn=1;std::array<int,n>a1;// Error: “n” is not a constant expressionconstintcn=2;std::array<int,cn>a2;// OK: “cn” is a constant expressionDefinition
An expression that belongs to any of the constant expression categories listed below is a constant expression.
C++98 constant expression categoriesIntegral constant expression (C++98)
In the following places, C++ requires expressions that evaluate to an integral or enumeration constant:
(including the dimensions in
other than the first)
constants
lengths
initializers
initializers
of integral or enumeration type
An expression satisfying all following conditions is an integral constant-expression :
It only involves the following entities:
literals of arithmetic types
enumerators
variables or static data members satisfying all following conditions:
They are const-qualified.
They are not volatile-qualified.
They are of integral or enumeration types.
They are initialized with constant expressions.
of integral or enumeration types
expressions
It does not use any floating-point literals, unless they are
to integral or enumeration types.
It does not apply any conversion to non-integral and non-enumeration types.
It does not use any of the following entities except in the operands of sizeof:
function
class object
pointer
reference
assignment operator
increment operator
decrement operator
function-call operator
comma operator
Other constant expression categories
Other expressions are considered constant expressions only for the purpose of
. Such a constant expression must be one of the following expressions:
an expression that evaluates to a
an expression that evaluates to a null pointer-to-member value
an arithmetic constant expression
an address constant expression
a reference constant expression
an address constant expression for a complete object type, plus or minus an integral constant expression
a pointer-to-member constant expression
An arithmetic constant expression is an expression satisfying the requirements for an integral constant expression, with the following exceptions:
Floating-point literals can be used without explicit conversion.
Conversions to floating-point types can be applied.
An address constant expression is an expression of pointer type satisfying all following conditions:
The pointer points to an lvalue designating an object of
, a
, or a
. The object is not a
of non-
type.
The pointer is created by one of the following methods:
explicitly using the address-of operator
implicitly using a non-type template parameter of pointer type
using an expression of array or function type
The expression does not call any function.
The expression uses explicit pointer conversions (except
) and the following operators without accessing the result object:
subscript operator
indirection operator
address-of operator
member access operator
If the subscript operator is used, one of its operands is an integral constant expression.
A reference constant expression is an expression of reference type satisfying all following conditions:
The reference designates an object of static storage duration, a non-type template parameter of reference type, or a function. The reference does not designate a member or base class of non-POD class type.
The expression does not call any function.
The expression uses explicit reference conversions (except
) and the following operators without accessing the result object:
subscript operator
indirection operator
address-of operator
member access operator
If the subscript operator is used, one of its operands is an integral constant expression.
A pointer-to-member constant expression is an expression of pointer-to-member type where the pointer is created by applying the address-of operator to a qualified identifier, optionally preceded by an explicit pointer-to-member conversion.
(until C++11)The following entities are permitted results of a constant expression :
temporary objects with
whose values satisfy the constraints listed below
non-temporary objects with static storage duration
non-
(since C++20)functions
A constant expression is either a glvalue
that refers to an entity that is a permitted result of a constant expression, or a prvalue core constant expression whose value satisfies the following constraints:
Each
refers to an entity that is a permitted result of a constant expression.
No
of
is an
.
Each
of
is one of the following values:
the address of an object with static storage duration
the address past the end of an object with static storage duration
the address of a non-immediate(since C++20) function
a
No constituent value of pointer-to-member type designates an immediate function.
(since C++11)
(until C++26)A constant expression is either a glvalue
that refers to an object or a non-
function, or a prvalue core constant expression whose value satisfies the following constraints:
Each
refers to an object or a non-immediate function.
No
of
is an
indeterminate or erroneous value
.
No constituent value of pointer type is a pointer to an immediate function or an
.
No constituent value of pointer-to-member type designates an immediate function.
(since C++26)When determining whether an expression is a constant expression,
is assumed not to be performed.
The C++98 definition of constant expressions is entirely within the collpase box. The following description applies to C++11 and later C++ versions.
Literal type
The following types are collectively called literal types :
possibly cv-qualified void
(since C++14)
an
of literal type
possibly cv-qualified class type that satisfies all following conditions:
It has a
(until C++20)
(since C++20).
All of its non-static non-variant data members and base classes are of non-volatile literal types.
It is one of the following types:
an
union type that satisfies one of the following conditions:
It has no
.
It has at least one variant member of non-volatile literal type.
a non-union aggregate type, and each of its
members satisfies one of the following conditions:
It has no variant member.
It has at least one variant member of non-volatile literal type.
a type with at least one constexpr constructor (template) that is not a copy or move constructor
Only objects of literal types can be created within a constant expression.
Core constant expression
A core constant expression is any expression whose evaluation would not evaluate any one of the following language constructs:
the
pointer, except in a
that is being evaluated as part of the expression, or when appearing in an implicit or explicit class member access expression
(since C++23) a control flow that passes through a declaration of a
with static or thread
that is not
usable in constant expressions
a function call expression that calls a function (or a constructor) that is not declared
constexprintn=std::numeric_limits<int>::max();// OK: max() is constexprconstexprintm=std::time(nullptr);// Error: std::time() is not constexpr
a function call to a constexpr function which is declared, but not defined
a function call to a constexpr function/constructor template instantiation where the instantiation fails to satisfy
constexpr function/constructor
requirements.
a function call to a constexpr virtual function, invoked on an object whose dynamic type is constexpr-unknown
an expression that would exceed the implementation-defined limits
an expression whose evaluation leads to any form of core language
or erroneous(since C++26) behavior, except for any potential undefined behavior introduced by
. constexprdoubled1=2.0/1.0;// OKconstexprdoubled2=2.0/0.0;// Error: not definedconstexprintn=std::numeric_limits<int>::max()+1;// Error: overflowintx,y,z[30];constexprautoe1=&y-&x;// Error: undefinedconstexprautoe2=&z[20]-&z[3];// OKconstexprstd::bitset<2>a;constexprboolb=a[2];// UB, but unspecified if detected
(until C++17) a
an lvalue-to-rvalue
unless applied to... a glvalue of type (possibly cv-qualified)
a non-volatile literal-type glvalue that designates an object that is
usable in constant expressions
intmain(){conststd::size_ttabsize=50;inttab[tabsize];// OK: tabsize is a constant expression// because tabsize is usable in constant expressions// because it has const-qualified integral type, and// its initializer is a constant initializerstd::size_tn=50;conststd::size_tsz=n;inttab2[sz];// Error: sz is not a constant expression// because sz is not usable in constant expressions// because its initializer was not a constant initializer}
a non-volatile literal-type glvalue that refers to a non-volatile object whose lifetime began within the evaluation of this expression
an lvalue-to-rvalue
or modification applied to a non-active member of a
or its subobject (even if it shares a common initial sequence with the active member)
an lvalue-to-rvalue implicit conversion on an object
an invocation of implicit copy/move constructor/assignment for a union whose active member is mutable (if any), with lifetime beginning outside the evaluation of this expression
(until C++20) an assignment expression that would change the active member of a union
conversion from
to a pointer-to-object type T* unless the pointer holds a null pointer value or points to an object whose type is
to T(since C++26)
whose operand is a glvalue that refers to an object whose dynamic type is constexpr-unknown(since C++20)
(until C++20) pseudo-destructor call
(until C++14) an increment or a decrement operator
(since C++14) modification of an object, unless the object has non-volatile literal type and its lifetime began within the evaluation of the expression constexprintincr(int&n){return++n;}constexprintg(intk){constexprintx=incr(k);// Error: incr(k) is not a core constant// expression because lifetime of k// began outside the expression incr(k)returnx;}constexprinth(intk){intx=incr(k);// OK: x is not required to be initialized// with a core constant expressionreturnx;}constexprinty=h(1);// OK: initializes y with the value 2// h(1) is a core constant expression because// the lifetime of k begins inside the expression h(1)
(since C++20) a destructor call or pseudo destructor call for an object whose lifetime did not begin within the evaluation of this expression
a
expression applied to a glvalue of polymorphic type and that glvalue refers to an object whose dynamic type is constexpr-unknown(since C++20)
a
, unless one of the following conditions is satisfied:(since C++20)The selected
is a replaceable global allocation function and the allocated storage is deallocated within the evaluation of this expression.
(since C++20)The selected allocation function is a non-allocating form with an allocated type T, and the placement argument satisfies all following conditions:
It points to:
an object whose type is similar to T, if T is not an array type, or
the first element of an object of a type similar to T, if T is an array type.
It points to storage whose duration began within the evaluation of this expression.
(since C++26)
a
, unless it deallocates a region of storage allocated within the evaluation of this expression(since C++20)
(since C++20) Coroutines: an
or a
(since C++20) a
when the result is unspecified
an equality or relational operator whose result is unspecified
(until C++14) an assignment or a compound assignment operator
(until C++26) a throw expression
(since C++26) a construction of an exception object, unless the exception object and all of its implicit copies created by invocations of
or
are destroyed within the evaluation of this expression constexprvoidcheck(inti){if(i<0)throwi;}constexprboolis_ok(inti){try{check(i);}catch(...){returnfalse;}returntrue;}constexprboolalways_throw(){throw12;returntrue;}static_assert(is_ok(5));// OKstatic_assert(!is_ok(-1));// OK since C++26static_assert(always_throw());// Error: uncaught exception
an
an invocation of the
macro
a
statement
a
or
expression or
(since C++26) that would throw an exception where no definition of the exception type is reachable(since C++26)
inside a lambda expression, a reference to this or to a variable defined outside that lambda, if that reference would be an odr-use voidg(){constintn=0;constexprintj=*&n;// OK: outside of a lambda-expression[=]{constexprinti=n;// OK: 'n' is not odr-used and not captured here.constexprintj=*&n;// Ill-formed: '&n' would be an odr-use of 'n'.};}note that if the ODR-use takes place in a function call to a closure, it does not refer to this or to an enclosing variable, since it accesses a closure's data member instead
// OK: 'v' & 'm' are odr-used but do not occur in a constant-expression// within the nested lambdaautomonad=[](autov){return[=]{returnv;};};autobind=[](autom){return[=](autofvm){returnfvm(m());};};// OK to have captures to automatic objects created during constant expression evaluation.static_assert(bind(monad(2))(monad)()==monad(2)());(since C++17)
Even if an expression E does not evaluate anything stated above, it is implementation-defined whether E is a core constant expression if evaluating E would result in
due to the use of [[
]] or [[
]].
Even if an expression E does not evaluate anything stated above, it is unspecified whether E is a core constant expression if evaluating E would evalute any of the following:
An operation with undefined behavior in the
.
An invocation of the
macro.
For the purposes of determining whether an expression is a core constant expression, the evaluation of the body of a member function of std::allocator<T> is ignored if T is a literal type.
For the purposes of determining whether an expression is a core constant expression, the evaluation of a call to a trivial copy/move constructor or copy/move assignment operator of a
is considered to copy/move the active member of the union, if any.
For the purposes of determining whether an expression is a core constant expression, the evaluation of an identifier expression that names a
bd has the following semantics:
If bd is an lvalue referring to the object bound to an invented reference ref, the behavior is as if ref were nominated.
Otherwise, if bd names an array element, the behavior is that of evaluating e[i], where e is the name of the variable initialized from the initializer of the structured binding declaration, and i is the index of the element referred to by bd.
Otherwise, if bd names a class member, the behavior is that of evaluating e.m, where e is the name of the variable initialized from the initializer of the structured binding declaration, and m is the name of the member referred to by bd.
(since C++26)During the evaluation of the expression as a core constant expression, all names and uses of *this that refer to an object or reference whose lifetime began outside the evaluation of the expression 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.
For such an object that is not
usable in constant expressions
(since C++20), the dynamic type of the object is constexpr-unknown.
For such a reference that is not usable in constant expressions(since C++20), 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.
Integral constant expression
Integral constant expression is an expression of integral or unscoped enumeration type implicitly converted to a prvalue, where the converted expression is a core constant expression.
If an expression of class type is used where an integral constant expression is expected, the expression is
contextually implicitly converted
to an integral or unscoped enumeration type.
Converted constant expression
A converted constant expression of type T is an expression
to type T, where the converted expression is a constant expression, and the implicit conversion sequence contains only:
constexpr
non-narrowing
non-narrowing
function-to-pointer conversions
from
null member pointer conversions
from
(since C++17)And if any
takes place, it can only be
.
The following contexts require a converted constant expression:
the constant-expression of
when the underlying type is fixed
integral and enumeration (until C++17)non-type
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.
The following contexts require a contextually converted constant expression of type bool:
Constituent entities
Informally, the constituent values and constituent references of an object obj are the scalar values and references that make up obj.
Formally, the constituent values of an object obj are defined as follows:
If obj has scalar type, the constituent value is the value of obj.
Otherwise, the constituent values are the constituent values of any direct
of obj other than
.
The constituent references of an object obj include the following references:
any direct members of obj that have reference type
the constituent references of any direct subobjects of obj other than inactive union members
The constituent values and constituent references of a variable var are defined as follows:
If var declares an object, the constituent values and references are the constituent values and references of that object.
If var declares a reference, the constituent reference is that reference.
For any constituent reference ref of a variable var, if ref is bound to a temporary object or subobject thereof whose lifetime is extended to that of ref, the constituent values and references of that temporary object are also constituent values and references of var, recursively.
Constexpr-representable entities
Every object with static storage duration is constexpr-referenceable at any point in the program.
An object with automatic storage duration is constexpr-referenceable from a point P if the object is defined in the function body that directly contains P.
voidf(){constexprintx=42;constexprconstint&ref=x;// OK, x is constexpr-referenceable hereconstint&r=42;// r binds to a temporary object with automatic storage durationconstexprconstint&ref2=r;// OK, the temporary is constexpr-referenceable here[&]{constexprconstint&ref=x;// Error: x is not constexpr-referenceable here};}(since C++26)Other objects (e.g. those with thread storage duration) are never constexpr-referenceable.
An object or reference x is constexpr-representable at a point P if all following conditions are satisfied:
For each constituent value of x that points to an object obj, obj is constexpr-referenceable from P.
For each constituent value of x that points past an object obj, obj is constexpr-referenceable from P.
For each constituent reference of x that refers to an object obj, obj is constexpr-referenceable from P.
Constant-initialized entities
A variable or temporary object obj is constant-initialized if all following conditions are satisfied:
Either it has an initializer, or its type is
.
The
of its initialization is a constant expression in the context of requiring a constant expression, except that if obj is an object, that full-expression may also invoke
for obj and its subobjects even if those objects are of non-literal class types.
(until C++26)A variable var is constant-initializable if all following conditions are satisfied:
The
of its initialization is a constant expression in the context of requiring a constant expression, where all
use the “ignore” evaluation semantic.
Immediately after the initializing declaration of var, the object or reference declared by var is constexpr-representable.
If the object or reference x declared by var 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 var.
A constant-initializable variable is constant-initialized if either it has an initializer, or its type is
.
voidf(){intax=0;// ax is constant-initializedthread_localinttx=0;// tx is constant-initializedstaticintsx;// sx is not constant-initialized (it doesn't have an initializer)constexprint&raa=ax;// OK, raa is constant-initializedconstexprint&rat=tx;// Error: rat is not constant-initialized// because it's not constexpr-representable herestaticconstexprint&rsa=ax;// Error: rsa is not constant-initialized// because it's not constexpr-representable at the nearest namespace scope}(since C++26)Usable in constant expressions
A variable is potentially-constant if it is a
or it has reference or non-volatile const-qualified integral or enumeration type.
A variable var is usable in constant expressions at a point P if:
var is constant-initialized,
var is potentially-constant,
var’s initializing declaration D is reachable from P and,
any of the following conditions is satisfied:
var is a constexpr variable.
var is not initialized to a
value.
P is in the same translation unit as D.
An object or reference is usable in constant expressions at a point P if it is
at P and(since C++26) it is one of the following entities:
a variable that is usable in constant expressions at P
a temporary object of non-volatile const-qualified literal type whose lifetime is extended to that of a variable that is usable in constant expressions at P
a
object
a non-mutable subobject of any of the above
a reference member of any of the above
Functions and variables needed for constant evaluation
Following expressions or conversions are potentially constant evaluated:
manifestly constant-evaluated expressions
potentially-evaluated expressions
immediate subexpressions of a
braced-enclosed initializer list
(constant evaluation may be necessary to determine whether
)
address-of expressions that occur within a
(constant evaluation may be necessary to determine whether such an expression is
)
subexpressions of one of the above that are not a subexpression of a nested
A function is needed for constant evaluation if it is a constexpr function and
an expression that is potentially constant evaluated.
A variable is needed for constant evaluation if it is either a constexpr variable or is of non-volatile const-qualified integral type or of reference type and the
that denotes it is potentially constant evaluated.
Definition of a defaulted function and instantiation of a
specialization or
specialization(since C++14) are triggered if the function or variable(since C++14) is needed for constant evaluation.
Constant subexpression
A constant subexpression is an expression whose evaluation as
of an expression e would not prevent e from being a
, where e is not any of the following expressions:
Notes
Feature-test macro ValueStdFeature
(C++20)
(DR11)Generation of function and variable definitions when
needed for constant evaluation
(C++20)Operations for dynamic storage duration in constexpr functions
(C++26)constexpr cast from void*: towards constexpr type-erasure
(C++26)constexpr placement new and new[]
(C++26)constexpr exceptions Example
Defect reports
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR Applied to Behavior as published Correct behavior
C++98 arithmetic constant expressions could not
involve variables and static data members they can
C++98 expressions involving string literals
could be integral constant expressions they are not
C++98 expressions involving volatile variables
could be integral constant expressions they are not
C++11 it was unclear whether string literals
are usable in constant expressions they are usable
C++11 volatile glvalues could be used in constant expressions prohibited
C++11 reinterpret_cast is prohibited in constant expressions,
but casting to and from void* could achieve the same effect prohibited conversions
from type cvvoid* to
a pointer-to-object type
C++11 undefined behavior was permitted;
all pointer subtraction was prohibited UB prohibited; same-array
pointer subtraction OK
C++11 for objects that are usable in constant expressions,
their mutable subobjects were also usable they are not usable
C++11 passing constants through constexpr
functions via references was not allowed allowed
C++11 converted constant expressions could only be prvalues can be lvalues
C++11 an address constant expression could not
designate the address one past the end of an array allowed
C++11 a typeid expression whose operand is of a
polymorphic class type was not a core constant
expression even if no runtime check is involved the operand constraint
is limited to glvalues of
polymorphic class types
C++11 functions needed for constant evaluation were
not required to be defined or instantiated required
C++11 core constant expressions could evaluate any
ODR-used reference inside lambda expressions some references could
not be evaluated
C++11 binding a prvalue pointer to local variable to a reference
was a constant expression it is not a
constant expression
C++11 core constant expressions could invoke constexpr function template
insantiations that do not satisfy the constexpr function requirements such instantiations
cannot be invoked
C++11 standard library undefined behaviors
were required to be diagnosed unspecified whether
they are diagnosed
C++98 the determination of constant expression might
depend on whether copy elision is performed assume that copy elision
is always performed
C++11 constant initialized lifetime-extended temporaries of const-
qualified literal types were not usable in constant expressions usable
C++11 integer literals were not constant expressions they are
C++11 non-member references local to an evaluation
made the evaluation non-constexpr non-member
references allowed
C++98 the resolution of
was not implementable assume that copy elision
is never performed
C++14 it was unclear whether macros in
can be used in constant evaluation va_arg forbidden,
va_start unspecified
C++11 invoking a constexpr virtual function on an object not usable
in constant expressions and whose lifetime began outside the
expression containing the invocation could be a constant expression it is not a
constant expression
C++20 (pseudo) destructor calls lacked
restrictions in constant evaluation restriction added
C++23 when evaluating a core constant expression, the control
flow could not pass through a declaration of a non-block variable it can
C++11 an indeterminate value could be a constant expression not a constant expression
C++20 variables of volatile-qualified types could be potentially-constant they are not
C++11 the violation of [[
]] was not required
to be detected during constant evaluation required
C++11 converted constant expressions did
not allow floating-point conversions allow non-narrowing
floating-point conversions
C++11 core constant expressions could not apply
lvalue-to-rvalue conversions to
glvalues can apply such
conversions
C++20 a variable without an initializer could only be
constant-initialized if its default-initialization
results in some initialization being performed can only be constant-
initialized if its type is
const-default-initializable
C++11
C++23 it was unspecified whether an expression violating
the constraints of [[
]] (C++11) or
[[
]] (C++23) is a core constant expression it is
implementation-defined
C++11 evaluating an expression containing an identifier expression
or *this that refers to an object or reference whose lifetime
began outside this evaluation is not a constant expression it can be a
constant expression See also