constexpr
- specifies that the value of a variable, structured binding(since C++26) or function can appear in constant expressionsThe constexpr specifier declares that it is possible to evaluate the value of the entities at compile time. Such entities can then be used where only compile time constant expressions are allowed (provided that appropriate function arguments are given).
A constexpr specifier used in an object declaration or non-static member function(until C++14) implies const.
A constexpr specifier used in the first declaration of a function or static data member(since C++17) implies inline. If any declaration of a function or function template has a constexpr specifier, then every declaration must contain that specifier.
[edit] constexpr variableA variable or variable template(since C++14) can be declared constexpr if all following conditions are satisfied:
If a constexpr variable is not translation-unit-local, it should not be initialized to refer to a translation-unit-local entity that is usable in constant expressions, nor have a subobject that refers to such an entity. Such initialization is disallowed in a module interface unit (outside its private module fragment, if any) or a module partition, and is deprecated in any other context.
(since C++20) [edit] constexpr functionA function or function template can be declared constexpr.
A function is constexpr-suitable if all following conditions are satisfied:
static_assert
declarationstypedef
declarations and alias declarations that do not define classes or enumerationsreturn
statement if the function is not a constructorExcept for instantiated constexpr functions, non-templated constexpr functions must be constexpr-suitable.
For a non-constructor constexpr function that is neither defaulted nor templated, if no argument values exist such that an invocation of the function could be an evaluated subexpression of a core constant expression, the program is ill-formed, no diagnostic required.
For a templated constexpr function, if no specialization of the function/class template would make the templated function constexpr-suitable when considered as a non-templated function, the program is ill-formed, no diagnostic required.
(until C++23)An invocation of a constexpr function in a given context produces the same result as an invocation of an equivalent non-constexpr function in the same context in all respects, with the following exceptions:
On top of the requirements of constexpr functions, a constructor also needs to satisfy all following conditions to be constexpr-suitable:
For a constexpr constructor that is neither defaulted nor templated, if no argument values exist such that an invocation of the function could be an evaluated subexpression of the initialization full-expression of some object subject to constant expression, the program is ill-formed, no diagnostic required.
(until C++23) [edit] constexpr destructorDestructors cannot be constexpr, but a trivial destructor can be implicitly called in constant expressions.
(until C++20)On top of the requirements of constexpr functions, a destructor also needs to satisfy all following conditions to be constexpr-suitable:
Because the noexcept
operator always returns true for a constant expression, it can be used to check if a particular invocation of a constexpr function takes the constant expression branch:
constexpr int f(); constexpr bool b1 = noexcept(f()); // false, undefined constexpr function constexpr int f() { return 0; } constexpr bool b2 = noexcept(f()); // true, f() is a constant expression(until C++17)
It is possible to write a constexpr function whose invocation can never satisfy the requirements of a core constant expression:
void f(int& i) // not a constexpr function { i = 0; } constexpr void g(int& i) // well-formed since C++23 { f(i); // unconditionally calls f, cannot be a constant expression }(since C++23)
Constexpr constructors are permitted for classes that are not literal types. For example, the default constructor of std::shared_ptr is constexpr, allowing constant initialization.
Reference variables can be declared constexpr (their initializers have to be reference constant expressions):
static constexpr int const& x = 42; // constexpr reference to a const int object // (the object has static storage duration // due to life extension by a static reference)
Even though try blocks and inline assembly are allowed in constexpr functions, throwing exceptions that are uncaught(since C++26) or executing the assembly is still disallowed in a constant expression.
If a variable has constant destruction, there is no need to generate machine code in order to call destructor for it, even if its destructor is not trivial.
A non-lambda, non-special-member, and non-templated constexpr function cannot implicitly become an immediate function. Users need to explicitly mark it consteval to make such an intended function definition well-formed.
(since C++20) [edit] Keywords [edit] ExampleDefines C++11/14 constexpr functions that compute factorials; defines a literal type that extends string literals:
#include <iostream> #include <stdexcept> // C++11 constexpr functions use recursion rather than iteration constexpr int factorial(int n) { return n <= 1 ? 1 : (n * factorial(n - 1)); } // C++14 constexpr functions may use local variables and loops #if __cplusplus >= 201402L constexpr int factorial_cxx14(int n) { int res = 1; while (n > 1) res *= n--; return res; } #endif // C++14 // A literal class class conststr { const char* p; std::size_t sz; public: template<std::size_t N> constexpr conststr(const char(&a)[N]): p(a), sz(N - 1) {} // constexpr functions signal errors by throwing exceptions // in C++11, they must do so from the conditional operator ?: constexpr char operator[](std::size_t n) const { return n < sz ? p[n] : throw std::out_of_range(""); } constexpr std::size_t size() const { return sz; } }; // C++11 constexpr functions had to put everything in a single return statement // (C++14 does not have that requirement) constexpr std::size_t countlower(conststr s, std::size_t n = 0, std::size_t c = 0) { return n == s.size() ? c : 'a' <= s[n] && s[n] <= 'z' ? countlower(s, n + 1, c + 1) : countlower(s, n + 1, c); } // An output function that requires a compile-time constant, for testing template<int n> struct constN { constN() { std::cout << n << '\n'; } }; int main() { std::cout << "4! = "; constN<factorial(4)> out1; // computed at compile time volatile int k = 8; // disallow optimization using volatile std::cout << k << "! = " << factorial(k) << '\n'; // computed at run time std::cout << "The number of lowercase letters in \"Hello, world!\" is "; constN<countlower("Hello, world!")> out2; // implicitly converted to conststr constexpr int a[12] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; constexpr int length_a = sizeof a / sizeof(int); // std::size(a) in C++17, // std::ssize(a) in C++20 std::cout << "Array of length " << length_a << " has elements: "; for (int i = 0; i < length_a; ++i) std::cout << a[i] << ' '; std::cout << '\n'; }
Output:
4! = 24 8! = 40320 The number of lowercase letters in "Hello, world!" is 9 Array of length 12 has elements: 0 1 2 3 4 5 6 7 8 0 0 0[edit] Defect reports
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR Applied to Behavior as published Correct behavior CWG 1358 C++11 templated constexpr functions also neededRetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4