General topics | ||||||||||||||||
Flow control | ||||||||||||||||
Conditional execution statements | ||||||||||||||||
Iteration statements (loops) | ||||||||||||||||
Jump statements | ||||||||||||||||
Functions | ||||||||||||||||
Function declaration | ||||||||||||||||
Lambda function expression | ||||||||||||||||
inline specifier | ||||||||||||||||
Dynamic exception specifications(until C++17*) | ||||||||||||||||
noexcept specifier(C++11) | ||||||||||||||||
Exceptions | ||||||||||||||||
Namespaces | ||||||||||||||||
Types | ||||||||||||||||
Specifiers | ||||||||||||||||
| ||||||||||||||||
Storage duration specifiers | ||||||||||||||||
Initialization | ||||||||||||||||
Expressions | ||||||||||||||||
Alternative representations | ||||||||||||||||
Literals | ||||||||||||||||
Boolean -Integer -Floating-point | ||||||||||||||||
Character -String -nullptr(C++11) | ||||||||||||||||
User-defined(C++11) | ||||||||||||||||
Utilities | ||||||||||||||||
Attributes(C++11) | ||||||||||||||||
Types | ||||||||||||||||
typedef declaration | ||||||||||||||||
Type alias declaration(C++11) | ||||||||||||||||
Casts | ||||||||||||||||
Memory allocation | ||||||||||||||||
Classes | ||||||||||||||||
Class-specific function properties | ||||||||||||||||
| ||||||||||||||||
Special member functions | ||||||||||||||||
Templates | ||||||||||||||||
Miscellaneous | ||||||||||||||||
General | |||||||||||||||||||||
| |||||||||||||||||||||
Literals | |||||||||||||||||||||
Operators | |||||||||||||||||||||
Conversions | |||||||||||||||||||||
Defines anexpression that can be evaluated at compile time.
Such expressions can be used as constant template arguments, array sizes, and in other contexts that require constant expressions, e.g.
int n=1;std::array<int, n> a1;// Error: “n” is not a constant expressionconstint cn=2;std::array<int, cn> a2;// OK: “cn” is a constant expression
An expression that belongs to any of the constant expression categories listed below is aconstant expression.
| (until C++11) | ||
The following expressions are collectively calledconstant expressions :
| (since C++11) (until C++14) | ||
The following entities arepermitted results of a constant expression :
Aconstant expression is either a glvaluecore constant expression 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:
| (since C++14) (until C++26) | ||
Aconstant expression is either a glvaluecore constant expression that refers to an object or a non-immediate function, or a prvalue core constant expression whose value satisfies the following constraints:
| (since C++26) |
When determining whether an expression is a constant expression,copy elision is assumed not to be performed.
The C++98 definition of constant expressions is entirely within the collapse box. The following description applies to C++11 and later C++ versions.
The following types are collectively calledliteral types :
(since C++17) |
Only objects of literal types can be created within a constant expression.
Acore constant expression is any expression whose evaluationwould not evaluate any one of the following language constructs:
Language construct | Version | Paper(s) |
---|---|---|
thethis pointer, except in aconstexpr function that is being evaluated as part of the expression, or when appearing in an implicit or explicit class member access expression | N2235 | |
a control flow that passes through a declaration of ablock variable with static or threadstorage duration that is notusable in constant expressions | (since C++23) | P2242R3 |
This section is incomplete Reason: Transfer the contents from the raw-HTML ordered list below to the wikitable above, while adding the papers/CWG issues that introduced the corresponding item to the standard. The mini-examples are not preserved, they can be combined to form a large example at the bottom of this page. |
constexprint n=std::numeric_limits<int>::max();// OK: max() is constexprconstexprint m=std::time(nullptr);// Error: std::time() is not constexpr
constexprdouble d1=2.0/1.0;// OKconstexprdouble d2=2.0/0.0;// Error: not definedconstexprint n=std::numeric_limits<int>::max()+1;// Error: overflowint x, y, z[30];constexprauto e1=&y-&x;// Error: undefinedconstexprauto e2=&z[20]-&z[3];// OKconstexprstd::bitset<2> a;constexprbool b= a[2];// UB, but unspecified if detected
int main(){conststd::size_t tabsize=50;int tab[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 initializer std::size_t n=50;conststd::size_t sz= n;int tab2[sz];// Error: sz is not a constant expression// because sz is not usable in constant expressions// because its initializer was not a constant initializer}
T*
unless the pointer holds a null pointer value or points to an object whose type issimilar toT
(since C++26)dynamic_cast
whose operand is a glvalue that refers to an object whose dynamic type is constexpr-unknown(since C++20)reinterpret_cast
constexprint incr(int& n){return++n;} constexprint g(int k){constexprint x= incr(k);// Error: incr(k) is not a core constant// expression because lifetime of k// began outside the expression incr(k)return x;} constexprint h(int k){int x= incr(k);// OK: x is not required to be initialized// with a core constant expressionreturn x;} constexprint y= 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)
typeid
expression applied to a glvalue of polymorphic typeand that glvalue refers to an object whose dynamic type is constexpr-unknown(since C++20)
| (since C++20) |
| (since C++26) |
constexprvoid check(int i){if(i<0)throw i;} constexprbool is_ok(int i){try{ check(i);}catch(...){returnfalse;}returntrue;} constexprbool always_throw(){throw12;returntrue;} static_assert(is_ok(5));// OKstatic_assert(!is_ok(-1));// OK since C++26static_assert(always_throw());// Error: uncaught exception
goto
statementdynamic_cast
ortypeid
expressionornew expression(since C++26) that would throw an exceptionwhere no definition of the exception type is reachable(since C++26)void g(){constint n=0; constexprint j=*&n;// OK: outside of a lambda-expression [=]{constexprint i= n;// OK: 'n' is not odr-used and not captured here.constexprint j=*&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 tothis 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 lambdaauto monad=[](auto v){return[=]{return v;};};auto bind=[](auto m){return[=](auto fvm){return fvm(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 expressionE does not evaluate anything stated above, it is implementation-defined whetherE is a core constant expression if evaluatingE would result inruntime-undefined behavior.
Even if an expressionE does not evaluate anything stated above, it is unspecified whetherE is a core constant expression if evaluatingE would evaluate any of the following:
For the purposes of determining whether an expression is a core constant expression, the evaluation of the body of a member function ofstd::allocator<T> is ignored ifT
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 aunion 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 astructured bindingbd has the following semantics:
| (since C++26) |
During the evaluation of the expression as a core constant expression, all identifier expressions 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 of that object or reference whose lifetime and that of all subobjects (including all union members) includes the entire constant evaluation.
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 iscontextually implicitly converted to an integral or unscoped enumeration type.
Aconverted constant expression of typeT
is an expressionimplicitly converted to typeT
, where the converted expression is a constant expression, and the implicit conversion sequence contains only:
(since C++17) |
And if anyreference binding takes place, it can only bedirect binding.
The following contexts require a converted constant expression:
| (since C++14) |
| (since C++26) |
Acontextually converted constant expression of typebool is an expression,contextually converted tobool, 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 typebool:
(until C++23) | |
(since C++17) (until C++23) | |
(since C++20) |
Constituent entitiesTheconstituent values of an objectobj are defined as follows:
Theconstituent references of an objectobj include the following references:
Theconstituent values andconstituent references of a variablevar are defined as follows:
For any constituent referenceref of a variablevar, ifref is bound to a temporary object or subobject thereof whose lifetime is extended to that ofref, the constituent values and references of that temporary object are also constituent values and references ofvar, recursively. Constexpr-representable entitiesObjects with static storage duration isconstexpr-referenceable at any point in the program. An objectobj with automatic storage duration isconstexpr-referenceable from a point An object or referencex isconstexpr-representable at a point
| (since C++26) | ||||||||
Constant-initialized entities
Usable in constant expressionsA variable ispotentially-constant if it is aconstexpr variable or it has reference or non-volatile const-qualified integral or enumeration type. A constant-initialized potentially-constant variablevar isusable in constant expressions at a point
Manifestly constant-evaluated expressionsThe following expressions (including conversions to the destination type) aremanifestly constant-evaluated :
Whether an evaluation occurs in a manifestly constant-evaluated context can be detected bystd::is_constant_evaluated and | (since C++20) |
Following expressions or conversions arepotentially constant evaluated:
A function isneeded for constant evaluation if it is a constexpr function andnamed by an expression that is potentially constant evaluated.
A variable isneeded for constant evaluation if it is either a constexpr variable or is of non-volatile const-qualified integral type or of reference type and theidentifier expression that denotes it is potentially constant evaluated.
Definition of a defaulted function and instantiation of afunction template specializationorvariable template specialization(since C++14) are triggered if the functionor variable(since C++14) is needed for constant evaluation.
Aconstant subexpression is an expression whose evaluation assubexpression of an expressione would not prevente from being acore constant expression, wheree is not any of the following expressions:
(since C++20) |
Feature-test macro | Value | Std | Feature |
---|---|---|---|
__cpp_constexpr_in_decltype | 201711L | (C++20) (DR11) | Generation of function and variable definitions whenneeded for constant evaluation |
__cpp_constexpr_dynamic_alloc | 201907L | (C++20) | Operations for dynamic storage duration inconstexpr functions |
__cpp_constexpr | 202306L | (C++26) | constexpr cast fromvoid*: towards constexpr type-erasure |
202406L | (C++26) | constexpr placementnew andnew[] | |
__cpp_constexpr_exceptions | 202411L | (C++26) | constexpr exceptions:[1],[2] |
This section is incomplete Reason: no example |
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
CWG 94 | C++98 | arithmetic constant expressions could not involve variables and static data members | they can |
CWG 366 | C++98 | expressions involving string literals could be integral constant expressions | they are not |
CWG 457 | C++98 | expressions involving volatile variables could be integral constant expressions | they are not |
CWG 1293 | C++11 | it was unclear whether string literals are usable in constant expressions | they are usable |
CWG 1311 | C++11 | volatile glvalues could be used in constant expressions | prohibited |
CWG 1312 | C++11 | reinterpret_cast is prohibited in constant expressions, but casting to and fromvoid* could achieve the same effect | prohibited conversions from typecvvoid* to a pointer-to-object type |
CWG 1313 | C++11 | undefined behavior was permitted; all pointer subtraction was prohibited | UB prohibited; same-array pointer subtraction OK |
CWG 1405 | C++11 | for objects that are usable in constant expressions, their mutable subobjects were also usable | they are not usable |
CWG 1454 | C++11 | passing constants through constexpr functions via references was not allowed | allowed |
CWG 1455 | C++11 | converted constant expressions could only be prvalues | can be lvalues |
CWG 1456 | C++11 | an address constant expression could not designate the address one past the end of an array | allowed |
CWG 1535 | C++11 | atypeid 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 |
CWG 1581 | C++11 | functions needed for constant evaluation were not required to be defined or instantiated | required |
CWG 1613 | C++11 | core constant expressions could evaluate any odr-used reference inside lambda expressions | some references could not be evaluated |
CWG 1694 | C++11 | binding the value of a temporary to a static storage duration reference was a constant expression | it is not a constant expression |
CWG 1872 | C++11 | core constant expressions could invokeconstexpr function template instantiations that do not satisfy theconstexpr function requirements | such instantiations cannot be invoked |
CWG 1952 | C++11 | standard library undefined behaviors were required to be diagnosed | unspecified whether they are diagnosed |
CWG 2022 | C++98 | the determination of constant expression might depend on whether copy elision is performed | assume that copy elision is always performed |
CWG 2126 | C++11 | constant initialized lifetime-extended temporaries of const- qualified literal types were not usable in constant expressions | usable |
CWG 2129 | C++11 | integer literals were not constant expressions | they are |
CWG 2167 | C++11 | non-member references local to an evaluation made the evaluation non-constexpr | non-member references allowed |
CWG 2278 | C++98 | the resolution ofCWG issue 2022 was not implementable | assume that copy elision is never performed |
CWG 2299 | C++14 | it was unclear whether macros in<cstdarg> can be used in constant evaluation | va_arg forbidden,va_start unspecified |
CWG 2400 | 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 |
CWG 2490 | C++20 | (pseudo) destructor calls lacked restrictions in constant evaluation | restriction added |
CWG 2552 | C++23 | when evaluating a core constant expression, the control flow could not pass through a declaration of a non-block variable | it can |
CWG 2558 | C++11 | an indeterminate value could be a constant expression | not a constant expression |
CWG 2647 | C++20 | variables of volatile-qualified types could be potentially-constant | they are not |
CWG 2763 | C++11 | the violation of[[noreturn]] was not requiredto be detected during constant evaluation | required |
CWG 2851 | C++11 | converted constant expressions did not allow floating-point conversions | allow non-narrowing floating-point conversions |
CWG 2907 | C++11 | core constant expressions could not apply lvalue-to-rvalue conversions tostd::nullptr_t glvalues | can apply such conversions |
CWG 2909 | 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 |
CWG 2924 | C++11 C++23 | it was unspecified whether an expression violating the constraints of [[noreturn]] (C++11) or[[assume]] (C++23) is a core constant expression | it is implementation-defined |
P2280R4 | 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 |
constexpr specifier(C++11) | specifies that the value of a variable or function can be computed at compile time[edit] |
(C++11)(deprecated in C++17)(removed in C++20) | checks if a type is a literal type (class template)[edit] |
C documentation forConstant expressions |