Defines an expression 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.
int n = 1; std::array<int, n> a1; // error: n is not a constant expression const int cn = 2; std::array<int, cn> a2; // OK: cn is a constant expression
A core constant expression is any expression whose evaluation would not evaluate any one of the following:
this
pointer, except in a constexpr function that is being evaluated as part of the expression constexpr int n = std::numeric_limits<int>::max(); // OK: max() is constexpr constexpr int m = std::time(nullptr); // Error: std::time() is not constexpr
constexpr double d1 = 2.0 / 1.0; // OK constexpr double d2 = 2.0 / 0.0; // Error: not defined constexpr int n = std::numeric_limits<int>::max() + 1; // Error: overflow int x, y, z[30]; constexpr auto e1 = &y - &x; // Error: undefined constexpr auto e2 = &z[20] - &z[3]; // OK constexpr std::bitset<2> a; constexpr bool b = a[2]; // UB, but unspecified if detected
int main() { const std::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; const std::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 }
dynamic_cast
reinterpret_cast
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: x is not required to be initialized // with a core constant expression return 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 the expression h(1)
typeid
expression applied to a glvalue of polymorphic type std::allocator<T>::allocate
, unless the selected allocation function is a replaceable global allocation function and the allocated storage is deallocated within the evaluation of this expression (since C++20) std::allocator<T>::deallocate
, unless it deallocates a region of storage allocated within the evaluation of this expression (since C++20) va_arg
macro, whether an invocation of the va_start
macro can be evaluated is unspecified goto
statement dynamic_cast
or typeid
expression that would throw an exception this
or to a variable defined outside that lambda, if that reference would be an odr-use void g() { const int n = 0; constexpr int j = *&n; // OK: outside of a lambda-expression [=] { constexpr int i = n; // OK: 'n' is not odr-used and not captured here. constexpr int 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 to // OK: 'v' & 'm' are odr-used but do not occur in a constant-expression // within the nested lambda auto 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) |
Note: Just being a core constant expression does not have any direct semantic meaning: an expression has to be one of the subsets of constant expressions (see below) to be used in certain contexts.
A constant expression is either.
| (since C++14) |
| (since C++20) |
void test() { static const int a = std::random_device{}(); constexpr const int& ra = a; // OK: a is a glvalue constant expression constexpr int ia = a; // Error: a is not a prvalue constant expression const int b = 42; constexpr const int& rb = b; // Error: b is not a glvalue constant expression constexpr int ib = b; // OK: b is a prvalue 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.
The following contexts require an integral constant expression:
| (until C++14) |
A converted constant expression 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:
| (since C++17) |
The following contexts require a converted constant expression:
| (since C++14) |
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:
(until C++23) |
(since C++17) (until C++23) |
(since C++20) |
Categories of constant expressions listed below are no longer used in the standard since C++14:
std::nullptr_t
or of a pointer type, which points to an object with static storage duration, one past the end of an array with static storage duration, to a function, or is a null pointer. Constant subexpressionA constant subexpression is an expression whose evaluation as subexpression of an expression
| (since C++17) |
In the list above, a variable is usable in constant expressions at a point P
if.
P
| (since C++20) |
An object or reference is usable in constant expressions if it is.
(since C++20) |
const std::size_t sz = 10; // sz is usable in constant expressions
The following expressions (including conversions to the destination type) are manifestly constant-evaluated:
| (since C++17) |
| (since C++20) |
Whether an evaluation occurs in a manifestly constant-evaluated context can be detected by To test the last two conditions, compilers may first perform a trial constant evaluation of the initializers. It is not recommended to depend on the result in this case. int y = 0; const int a = std::is_constant_evaluated() ? y : 1; // Trial constant evaluation fails. The constant evaluation is discarded. // Variable a is dynamically initialized with 1 const int b = std::is_constant_evaluated() ? 2 : y; // Constant evaluation with std::is_constant_evaluation() == true succeeds. // Variable b is statically initialized with 2 | (since C++20) |
Following expressions or conversions are potentially constant evaluated:
&
) expressions that occur within a templated entity (constant evaluation may be necessary to determine whether such an expression is value-dependent) A function is needed for constant evaluation if it is a constexpr function and named by 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 id-expression that denotes it is potentially constant evaluated.
Definition of a defaulted function and instantiation of a function template specialization or variable template specialization (since C++14) are triggered if the function or variable (since C++14) is needed for constant evaluation.
Implementations are not permitted to declare library functions as constexpr unless the standard says the function is constexpr.
Named return value optimization (NRVO) is not permitted in constant expressions, while return value optimization (RVO) is mandatory.
Feature-test macro | Value | Std | Comment |
---|---|---|---|
__cpp_constexpr_in_decltype | 201711L |
(C++11) (DR) | Generation of function and variable definitions when needed for constant evaluation |
__cpp_constexpr_dynamic_alloc | 201907L | (C++20) | Operations for dynamic storage duration in constexpr functions |
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
CWG 1293 | C++11 | it was unspecified 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 from void* could achieve the same effect | prohibited conversions from type cv void* 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 | 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 |
CWG 1581 | C++11 | functions needed for constant evaluation were not required to be defined or instantiated | required |
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 1952 | C++11 | standard library undefined behaviors were required to be diagnosed | unspecified whether they are diagnosed |
CWG 2126 | C++11 | constant initialized lifetime-extended temporaries of const- qualified literal types were not usable in constant expressions | usable |
CWG 2167 | C++11 | non-member references local to an evaluation made the evaluation non-constexpr | non-member references allowed |
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 2418 | C++11 | it was unspecified which object or reference that are not variables are usable in constant expressions | specified |
CWG 2490 | C++20 | (pseudo) destructor calls lacked restrictions in constant evaluation | restriction added |
constexpr specifier(C++11) | specifies that the value of a variable or function can be computed at compile time |
(C++11)(deprecated in C++17)(removed in C++20) | checks if a type is a literal type (class template) |
C documentation for Constant expressions |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/language/constant_expression