{{short description|C/C++ specifier referring to constant expression}} {{lowercase title}} '''{{mono|constexpr}}''' is a specifier keyword in the C and C++ programming languages which, roughly speaking, specifies that something may be evaluated at compile time.<ref name="constexpr-cpp11">{{Cite web|title=constexpr specifier (since C++11)|url=https://en.cppreference.com/w/cpp/language/constexpr.html|publisher=cppreference.com|author=cppreference.com|website=cppreference.com|access-date=14 April 2026}}</ref> Unlike the usual {{mono|const}}, which specifies read-only access, <code>constexpr</code> is a stronger form that implies <code>const</code> (in most contexts). While in C this is limited only to objects,<ref name="constexpr-c23">{{Cite web|title=constexpr specifier (since C23)|url=https://en.cppreference.com/w/c/language/constexpr.html|publisher=cppreference.com|author=cppreference.com|website=cppreference.com|access-date=14 April 2026}}</ref> <code>constexpr</code> may be used on objects, functions, or structured bindings in C++.<ref name="constexpr-cpp11"/>

Additional keywords in the C++ family of "<code>const</code>" keywords include <code>consteval</code>{{refn|name="cppref_consteval"|{{cite web |author=<!-- not stated --> |date=<!-- not stated--> |title=consteval specifier (since C++20) |url=https://en.cppreference.com/cpp/language/consteval |website=cppreference.com. |location= |publisher=cppreference.com. |access-date=3 May 2026 }} }}, used for guaranteeing a function executes at compile time and compile time only, and <code>constinit</code>, used for guaranteeing static/thread storage duration, ensuring compile-time initialization (but not immutability){{refn|name="cppref_constinit"|{{cite web |author=<!-- not stated --> |date=<!-- not stated --> |title=constinit specifier (since C++20) |url=https://en.cppreference.com/cpp/language/constinit |website=cppreference.com. |location= |publisher=cppreference.com. |access-date= 3 May 2026 }}}}.

== Background == The word <code>constexpr</code> is a portmanteau of ''constant expression''<ref name="constexpr-microsoft">{{Cite web|title=constexpr (C++)|url=https://learn.microsoft.com/en-us/cpp/cpp/constexpr-cpp|publisher=Microsoft Learn|author=Microsoft Learn|date=22 February 2023|website=learn.microsoft.com}}</ref>, first introduced in C++11. Prior to the introduction of <code>constexpr</code>, options for specifying compile-time constants and functions in C++ were limited to preprocessor macros (such as <syntaxhighlight lang="cpp" inline>#define PI 3.1415926535</syntaxhighlight> or procedural macros like <syntaxhighlight lang="cpp" inline>#define SQUARE(x) ((x) * (x))</syntaxhighlight>), which performed textual substitution and thus lacked the type safety of a core language feature, or declaring an enumerated constant (such as <syntaxhighlight lang="cpp" inline>enum { WINDOW_SIZE = 600 };</syntaxhighlight>), which was limited only to integral types. A particular motivation for the development of compile-time expressions was that <syntaxhighlight lang="cpp" inline>std::numeric_limits<T>::max()</syntaxhighlight>, although being equivalent to the macro <code>INT_MAX</code>, produced a non-constant expression.<ref name="gen-const-expr-rev5">{{Cite web|title=Generalized Constant Expressions - Revision 5|url=https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2235.pdf|website=open-std.org|author=Gabriel Dos Reis, Bjarne Stroustrup, Jens Maurer|date=3 November 2006}}</ref>

Initial proposals for generalised constant expressions and compile-time expressions were first proposed for inclusion into C++ by Gabriel Dos Reis in 2003<ref>{{Cite web|title=Generalized Constant Expressions|url=https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1521.pdf|author=Gabriel Dos Reis|website=open-std.org|publisher=WG21|date=21 September 2003}}</ref>, proposing generalizing constant expressions to include ''constant-valued functions'', functions which could be evaluated at compile time, with a particular goal being to improve type-safety and portability.<ref name="gen-const-expr-rev5"/> This proposed was further revised with the co-authorship of Bjarne Stroustrup and Jens Maurer in 2006 to introduce the <code>constexpr</code> keyword, along with including ''user-defined literals'' (objects of user-defined types with <code>constexpr</code> constructors and destructors) into the definition of constant expressions.<ref name="gen-const-expr-rev5"/>, and adopted into the draft for C++11 in July 2007.<ref>{{Cite web|title=Trip report: June 2025 ISO C++ standards meeting (Sofia, Bulgaria)|url=https://herbsutter.com/2025/06/21/trip-report-june-2025-iso-c-standards-meeting-sofia-bulgaria/|publisher=Herb Sutter|author=Herb Sutter|website=herbsutter.com|date=21 June 2025}}</ref> Herb Sutter, chairman of the C++ committee, in 2026 described the adoption of <code>constexpr</code> as one of the most 'momentous' polls of C++ history.<ref name="herbsutter_cpp26">{{cite web |last=Sutter |first=Herb |date=21 June 2025 |title=Trip report: June 2025 ISO C++ standards meeting (Sofia, Bulgaria) |url=https://herbsutter.com/2025/06/21/trip-report-june-2025-iso-c-standards-meeting-sofia-bulgaria/ |website=herbsutter.com. |location= |publisher=herbsutter.com |access-date=10 April 2026 |quote= Until today, perhaps the most momentous single feature poll of C++’s history was the poll in Toronto in July 2007 to adopt Bjarne Stroustrup’s and Gabriel Dos Reis’ first “constexpr” paper into draft C++11. Looking back now, we can see what a tectonic shift that started for C++. |author-link=Herb Sutter}}</ref>

C++20 further introduced two keywords of the "<code>const</code> family": <code>consteval</code> and <code>constinit</code>.<ref name="immediate-functions">{{Cite web|title=Immediate functions|url=https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1073r2.html|publisher=WG21|author=Richard Smith, Andrew Sutton, Daveed Vandevoorde|website=open-std.org|date=4 October 2018}}</ref><ref name="adding-constinit">{{Cite web|title=Adding the constinit keyword|url=https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1143r2.html|publisher=WG21|author=Eric Fiselier|website=open-std.org|date=18 July 2019}}</ref> With introduction of compile-time reflection in C++26, a proposal was made for <code>consteval</code> variables, but was not added.<ref>{{Cite web|title=Consteval-only Values and Consteval Variables|url=https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3603r0.html|author=Barry Rezvin, Peter Dimov|website=open-std.org|publisher=WG21|date=13 March 2025}}</ref>

<code>constexpr</code> was later introduced into C, beginning in C23.<ref name="constexpr-c23"/><ref>{{Cite web|title=The constexpr specifier for object definitions|url=https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3018.htm|website=open-std.org|publisher=WG14|author=Alex Gilding, Jens Gustedt|date=6 July 2022}}</ref>

== Semantics == The primary usage of <code>constexpr</code> is to allow for evaluating complex calculations at compile time, avoiding runtime overhead such as additional stack frames or memory<ref name="constexpr-microsoft"/> without relying on preprocessor directives, as well as preventing certain cases of undefined behavior.<ref name="expressions-constant">{{Cite web|title=7 - Expressions, 7.7 - Constant expressions|url=https://eel.is/c++draft/expr.const|publisher=WG21|author=WG21|website=eel.is|access-date=14 April 2026}}</ref>

=== Variables === A variable or a variable template may be declared <code>constexpr</code> if it is a definition, is a literal type, is initialized at declaration, and is constant-initializable.<ref>{{Cite web|title=Constant expressions - Constant initialized entities|url=https://en.cppreference.com/w/cpp/language/constant_expression.html#Constant-initialized_entities|publisher=cppreference.com|author=cppreference.com|website=cppreference.com|access-date=14 April 2026}}</ref> Such a <code>constexpr</code> variable is implicitly made {{mono|const}}. References may also be made <code>constexpr</code> provided they are initialized by constant expression and any implicit conversions invoked during initialization are also constant expressions.<ref name="constexpr-microsoft"/>

<syntaxhighlight lang="cpp"> import std;

using std::array;

// Declare compile-time constants constexpr double EARTH_GRAVITATIONAL_ACCELERATION = 9.8; constexpr double MOON_GRAVITATIONAL_ACCELERATION = EARTH_GRAVITATIONAL_ACCELERATION / 6.0; constexpr size_t MAX_LENGTH = 500;

// Creates an array of ints of length 500, using compile-time constant MAX_LENGTH array<int, MAX_LENGTH> numbers; </syntaxhighlight>

C++26 allowed <code>constexpr</code> structured bindings<ref>{{Cite web|title=Structured binding declaration (since C++17)|url=https://en.cppreference.com/cpp/language/structured_binding|author=cppreference.com|website=cppreference.com|publisher=cppreference.com|access-date=11 May 2026}}</ref>, which may bind to aggregate types (i.e. structs), arrays, and pairs/tuples.<ref name="constexpr_sb_ref"/> <syntaxhighlight lang="cpp"> struct Point { int x; int y; };

constexpr int NUMS[3] = {1, 2, 3};

// a = 1, b = 5 constexpr auto [a, b] = Point{.x = 1, .y = 5}; // id = 3, name = "John Doe", score = 95 constexpr auto [id, name, score] = std::make_tuple(3, "John Doe", 95); // x = 1, y = 2, z = 3 constexpr auto [x, y, z] = NUMS; </syntaxhighlight>

=== Pointers and references === In C, pointers (except <code>nullptr</code>), variably modified types, atomic types and {{mono|volatile}} types may not be <code>constexpr</code>.

In C++, <code>constexpr</code> pointers and references are subject to slightly different restrictions than regular <code>constexpr</code> variables. In <code>constexpr</code> pointers, the pointer's held address must be an address of a variable with static storage duration, and is a constant pointer. Pointer arithmetic on these addresses (if not an array) and addresses of stack variables are not constant expressions. <syntaxhighlight lang="cpp"> import std;

int main() { int x = 3; static float val = 3.0f;

// Error (automatic storage duration) // constexpr int* ptr = &x;

// OK (static storage duration) constexpr float* address = &val; *address = 4.5f;

std::println("{}", val); // prints 4.5 }

</syntaxhighlight>

Meanwhile, <code>constexpr</code> references bind only either to variables of static storage duration or <code>constexpr</code> variables (regardless of storage duration).{{refn|name="constexpr_sb_ref"| {{cite web |last1=Jabot |first1=Corentin |last2=Bi |first2=Brian |date=12 November 2024 |title=constexpr structured bindings and references to constexpr variables |url=https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2686r5.pdf |website=open-std.org. |location= |publisher=open-std.org. |access-date= 10 May 2026 }} }} <syntaxhighlight lang="cpp"> import std;

int main() { static char ch = 'A'; constexpr char& ref1 = ch; ref1 = 'c'; std::println("{}", ref1); // prints 'c'

constexpr int num = 100; constexpr int& ref2 = num;

std::println("{}", ref2 - 2); // prints 98 } </syntaxhighlight>

=== Functions === A <code>constexpr</code> function is a function whose return value may be computed at compile time (i.e. when the arguments are constant expressions), and when called at runtime, behaves as a regular function.<ref name="constexpr-microsoft"/> A <code>constexpr</code> function evaluated at compile time will halt compilation once undefined behavior is invoked.<ref name="expressions-constant"/> <code>constexpr</code> functions are implicitly {{mono|inline}}.<ref name="constexpr-cpp11"/> <syntaxhighlight lang="cpp"> constexpr double div(double a, double b) noexcept { return a / b; }

constexpr double x = div(1, 0); // Prevents compilation, due to invoking undefined behavior </syntaxhighlight>

Because the return types of <code>constexpr</code> functions may be known at compile time, they may be invoked at compile time for use in compile-time expressions.

<syntaxhighlight lang="cpp"> constexpr int getFive() noexcept { return 5; }

int numbers[getFive() + 7]; // Creates an array of 12 ints </syntaxhighlight>

Coroutines may not be <code>constexpr</code>. Historically, <code>constexpr</code> functions had far more restrictions, including the disallowing of multiple <code>return</code> statements, <code>try</code> blocks, and inline assembly blocks, all of which have been gradually relaxed with each revision.<ref name="constexpr-cpp11"/><ref>{{Cite web|title=Relaxing constraints on constexpr functions|url=https://open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3597.html|publisher=WG21|author=Richard Smith|date=15 March 2013}}</ref>

C++17 allowed closure types and lambda functions to be used in constant evaluation content.<ref name="cppref_constexpr"/>

Class methods and overloadable operators may also be declared with <code>constexpr</code>. Prior to C++14, <code>constexpr</code> methods had implicit <code>const</code> access, preventing them from being able to manipulate the class.<ref name="constexpr-microsoft"/> Prior to C++20, virtual functions could not be <code>constexpr</code>.<ref name="constexpr-cpp11"/><ref name="dimov-virtual">{{Cite web|title=Allowing Virtual Functions Calls in Constant Expressions|url=https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1064r0.html|author=Peter Dimov, Vassil Vassilev|website=open-std.org|publisher=WG21|date=4 May 2018}}</ref>

=== Constructors and destructors === A <code>constexpr</code> constructor is one such that it allows the class to be initialized and declared at compile time. <code>constexpr</code> constructors are subject to the same requirements as <code>constexpr</code> functions.<ref name="cppref_constexpr"/> Until C++26, classes with <code>virtual</code> base classes could not have <code>constexpr</code> constructors. The introduction of <code>constexpr</code> virtual inheritance seeks eventually allowing for <code>constexpr</code> stream formatting through a <code>constexpr</code> constructor for <code>std::ios_base</code>.<ref name="constexpr-virtual-inheritance">{{Cite web|title=constexpr virtual inheritance|url=https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3533r2.html|publisher=WG21|author=Hana Dusíková|website=open-std.org|date=17 February 2025}}</ref> The implicitly generated constructor is guaranteed to be <code>constexpr</code> if the class is a literal type.<ref>{{Cite web|title=Default constructors|url=https://en.cppreference.com/w/cpp/language/default_constructor.html|publisher=cppreference.com|author=cppreference.com|website=cppreference.com|access-date=14 April 2026}}</ref><ref>{{Cite web|title=Constant expressions - Literal type|url=https://en.cppreference.com/w/cpp/language/constant_expression.html#Literal_type|publisher=cppreference.com|author=cppreference.com|website=cppreference.com|date=14 April 2026}}</ref>

A <code>constexpr</code> destructor (introduced in C++20), meanwhile, is a destructor allowing destruction of the object at compile time. Like constructors, <code>constexpr</code> destructors are subject to the same requirements as <code>constexpr</code> functions.<ref name="cppref_constexpr"/> The primary motivations for the introduction of <code>constexpr</code> destructors were for allowing the usage of non-trivial classes at compile-time, such as <code>std::string</code> and <code>std::vector</code>, the latter of which is used extensively in the API of <code>std::meta</code>'s compile-time reflection.<ref>{{Cite web|title=P2996R4 - Reflection for C++26|url=https://isocpp.org/files/papers/P2996R4.html|author=Wyatt Childers|display-authors=etal|date=26 June 2024|publisher=WG21|website=isocpp.org}}</ref> This now allows for non-trivial allocations and destructions in compile-time contexts.<ref name="more-constexpr-containers">{{Cite web|title=More constexpr containers|url=https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0784r7.html|author=Peter Dimov|website=open-std.org|publisher=WG21|date=19 July 2019}}</ref> The implicitly generated destructor is guaranteed to be <code>constexpr</code> if the class is a literal type.<ref>{{Cite web|title=Destructors|url=https://en.cppreference.com/w/cpp/language/destructor.html|publisher=cppreference.com|author=cppreference.com|website=cppreference.com|access-date=14 April 2026}}</ref> Like <code>constexpr</code> constructors, <code>constexpr</code> destructors historically disallowed destruction of classes with <code>virtual</code> base classes. In C++26, various standard library classes, which have been historically runtime-only, have been made compile-time eligible through <code>constexpr</code> destructors.<ref name="constexpr-containers">{{Cite web|title=constexpr containers and adaptors|url=https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3372r3.html|publisher=WG21|author=Hana Dusíková|date=11 February 2025|website=open-std.org}}</ref>

A class with static members that are instances of itself may be <code>constexpr</code>, but the fields inside the class must first be declared <code>const</code> while the <code>constexpr</code> declarations must reside outside the class. Trying to use declare a <code>constexpr</code> instance of a class as a {{mono|static}} member of itself fails as no definition of an object may be an incomplete type, which the class is incomplete until it is closed.<ref>{{Cite web|title=Draft C++ Standard - Declarations and definitions|url=https://eel.is/c++draft/basic#def-5|quote=In the definition of an object, the type of that object shall not be an incomplete type ([basic.types.general]), an abstract class type ([class.abstract]), or a (possibly multidimensional) array thereof.|publisher=WG21|author=WG21|website=eel.is|date=23 April 2026}}</ref> <syntaxhighlight lang="cpp"> struct Color { uint8_t r; uint8_t g; uint8_t b;

constexpr Color(uint8_t r, uint8_t g, uint8_t b) noexcept: r{r}, g{g}, b{b} {}

constexpr ~Color() = default;

static const Color BLACK; static const Color RED; static const Color GREEN; static const Color YELLOW; static const Color BLUE; static const Color MAGENTA; static const Color CYAN; static const Color WHITE; };

inline constexpr Color Color::BLACK = Color(0, 0, 0); inline constexpr Color Color::RED = Color(255, 0, 0); inline constexpr Color Color::GREEN = Color(0, 255, 0); inline constexpr Color Color::YELLOW = Color(255, 255, 0); inline constexpr Color Color::BLUE = Color(0, 0, 255); inline constexpr Color Color::MAGENTA = Color(255, 0, 255); inline constexpr Color Color::CYAN = Color(0, 255, 255); inline constexpr Color Color::WHITE = Color(255, 255, 255); </syntaxhighlight>

== Compile-time if statements == C++ features two forms of compile-time if statements: <code>if constexpr</code> and <code>if consteval</code>.<ref name="cppreference-if">{{Cite web|title=if statement|url=https://en.cppreference.com/w/cpp/language/if.html|publisher=cppreference.com|author=cppreference.com|website=cppreference.com|access-date=14 April 2026}}</ref>

The former, <code>if constexpr</code>, introduced in C++17, allows for conditional branching at compile time. It requires that the condition be a constant expression convertible to <code>bool</code>.<ref name="cppreference-if"/> <code>if constexpr</code> discards the branch that is not taken, preventing it from compiling. This allows for conditional compilation without usage of the preprocessor. However, the discarded branch, even if not compiled, is required by the compiler to be syntactically valid or accepted.<ref>{{Cite web|title=P0292R2: constexpr if: A slightly different syntax|url=https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0292r2.html|publisher=WG21|author=Jens Maurer|date=20 June 2016|website=open-std.org}}</ref> <code>return</code> statements in a discarded statement do not participate in function return type deduction.

<syntaxhighlight lang="cpp"> import std;

using std::conditional_t; using std::is_pointer_v; using std::remove_pointer_t;

template <typename T> constexpr auto getValue(T t) noexcept -> conditional_t<is_pointer_v<T>, remove_pointer_t<T>, T> { if constexpr (is_pointer_v<T>) { return *t; } else { return t; } }

int main() { int* numbers = new int[5]{1, 2, 3, 4, 5}; int firstNumber = getValue(numbers); int five = getValue(5);

delete numbers; } </syntaxhighlight>

The latter, <code>if consteval</code>, introduced in C++23, acts as a <code>if constexpr</code> where the condition is whether or not the <code>if</code> condition is being evaluated at compile time, rather than at runtime.<ref>{{Cite web|title=if consteval|url=https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p1938r3.html|author=Barry Revzin, Richard Smith, Andrew Sutton, Daveed Vandevoorde|website=open-std.org|publisher=WG21|date=22 March 2021}}</ref>

<syntaxhighlight lang="cpp"> template <typename T> constexpr T* arrayOfLength(size_t n) { if consteval { // Array may not leave scope of a compile-time expression return nullptr; } else { // At runtime, allow returning a pointer to a heap-allocated array return new T[n]; } } </syntaxhighlight>

<code>if consteval</code> introduces an additional syntax: <syntaxhighlight lang="cpp" inline>if !consteval { /* stmt1 */ } else { /* stmt2 */ }</syntaxhighlight> is equivalent to <syntaxhighlight lang="cpp" inline>if consteval { /* stmt2 */ } else { /* stmt1 */ }</syntaxhighlight>.<ref name="cppreference-if"/>

== Evolution == {{Expand section|date=April 2026}} The <code>constexpr</code> specifier has evolved with each passing C++ standard revision either lifting restrictions on <code>constexpr</code> or introducing new contexts for the keyword's usage, as the historical <code>constexpr</code> in C++11 was subject to far more restrictions than in contemporary C++.

=== C++11 === In the 2008 draft of C++11, <code>constexpr</code> functions were permitted to call themselves recursively.<ref name="issueswithconstexpr">{{cite web |author=Lawrence Crowl |date=5 February 2009 |title=Issues with Constexpr |url=https://open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2826.html |website=open-std.org. |location= |publisher=WG21 |access-date=15 April 2026}}</ref> Later in 2010, the constexpr functions allowed to pass their parameters as const-reference<ref name="const T&">{{cite web |last=Stroustrup |first=Bjarne |date=14 February 2010 |title=Constexpr functions with const reference parameters (a summary) |url=https://open-std.org/JTC1/SC22/WG21/docs/papers/2010/n3039.pdf |website=open-std.org. |location= |publisher=WG21 |access-date=15 April 2026}}</ref> and in 2011, <code>static_assert</code> checks and <code>using</code> statements were allowed within the contexts of <code>constexpr</code> functions.<ref name="sttcsrt">{{cite web |last=Merill |first=Jason |date=25 March 2011 |title=static_assert and list-initialization in constexpr functions |url=https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3268.htm |website=open-std.org |location= |publisher=WG21 |access-date=15 April 2026}}</ref> In the final C++11 standard, <code>constexpr</code> functions were allowed only one return statement.<ref name="constexpr-cpp11"/>

=== C++14 === C++14 lifted the restriction that all <code>constexpr</code> methods were implicitly <code>const</code>, allowing <code>constexpr</code> methods to be able to change values of member variables.<ref name="constexpr-microsoft"/>

C++14 allowed multiple return statements, control flow blocks such as <code>if</code>/<code>else</code> and <code>switch</code>, loops, and variable declarations within <code>constexpr</code> functions.<ref name="C++14_constexpr">{{Cite web|title=Relaxing constraints on constexpr functions|url=https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3597.html|author=Richard Smith|date=15 March 2013|publisher=WG21|website=open-std.org}}</ref> C++14 also allowed constexpr functions to have <code>void</code> return type. The following example shows a prime number checker which works at compile time.

<syntaxhighlight lang="C++"> constexpr bool isPrime(uint64_t number) noexcept { if (number < 2) { return false; } else if (number == 2 || number == 3) { return true; } else if (number % 2 == 0 || number % 3 == 0) return false; } for (uint64_t i = 5; i * i <= number; i += 6) { if (number % i == 0 || number % (i + 2) == 0) { return false; } } return true; }

static_assert(isPrime(264223787557)); </syntaxhighlight>

=== C++17 === C++17 specified that a <code>constexpr</code> specifier in the declaration of a function or a static member variable implicitly makes it {{mono|inline}}.<ref name="constexpr-cpp11"/> C++17 introduced <code>if constexpr</code>, influencing template metaprogramming.<ref name="cppreference-if"/>

Since C++17, closure types and lambda functions can be used in constant expressions.<ref name="cppref_constexpr">{{cite web |author=<!-- not stated --> |date=2026 |title=constexpr specifier (since C++11) |url=https://en.cppreference.com/cpp/language/constexpr |website=cppreference.com. |location= |publisher=cppreference.com. |access-date=25 April 2026}}</ref> All lambdas are implicitly <code>constexpr</code>.<ref name="cppref_constexpr"/> <syntaxhighlight lang="C++"> constexpr int FACTOR = 10;

constexpr auto scaleBy = [FACTOR](int x) -> int { return x * FACTOR; };

static_assert(scaleBy(4) == 40); </syntaxhighlight>

=== C++20 === C++20 relaxed the constraints for <code>constexpr</code> evaluation in various contexts<ref name="cppref_constexpr"/><ref name="dimov-virtual"/><ref name="more-constexpr-containers"/>, including virtual function calls, transient heap allocation, <code>constexpr</code> destructors<ref name="constexpr-cpp11"/><ref name="more-constexpr-containers"/> and others. Heap allocations in <code>constexpr</code> contexts must be known to be deallocated within <code>constexpr</code> contexts.<ref name="more-constexpr-containers"/>

C++20 lifted the restriction on <code>constexpr</code> virtual methods.<ref name="constexpr-cpp11"/><ref name="dimov-virtual"/>

<syntaxhighlight lang="cpp"> class Base { public: virtual constexpr size_t f() const { return sizeof(int); }

constexpr virtual ~Base() = default; };

class MyIntArray : public Base { private: int* a; const size_t length; public: constexpr size_t f() const override { return length; }

constexpr MyIntArray(size_t n): a{new int[n]}, length{n} {}

constexpr ~MyIntArray() override { delete[] a; }

constexpr int& operator[](size_t i) { return a[i]; }

constexpr const int& operator[](size_t i) const { return a[i]; }

MyIntArray(const MyIntArray&) = delete; MyIntArray& operator=(const MyIntArray&) = delete; }; </syntaxhighlight>

=== C++23 === C++23 allowed functions to contain <code>goto</code> statements, <code>try</code> blocks, static variables, and inline assembly.<ref name="constexpr-cpp11"/> C++23 further introduced <code>if consteval</code>.<ref name="cppreference-if"/>

=== C++26 === C++26 allows the usage of virtual inheritance in constructors and destructors declared with <code>constexpr</code>.<ref name="constexpr-virtual-inheritance"/> Support for <code>constexpr</code> structured bindings was added<ref name="constexpr_sb_ref"/>, <code>constexpr</code> casting from <code>void*</code><ref>{{Cite web|title=constexpr cast from void*: towards constexpr type-erasure|url=https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2738r1.pdf|author=Corentin Jabot, David Ledger|publisher=WG21|website=open-std.org|date=13 February 2023}}</ref>, <code>constexpr</code> placement {{mono|new}}<ref>{{Cite web|title=constexpr placement new|url=https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2747r2.html|author=Barry Rezvin|website=open-std.org|publisher=WG21|date=19 March 2024}}</ref>, as well as <code>constexpr</code> exception throwing.<ref>{{Cite web|title=Allowing exception throwing in constant-evaluation|url=https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3068r6.html|author=Hana Dusíková|publisher=WG21|date=19 November 2024|website=open-std.org}}</ref> Further support for <code>constexpr</code> standard library types was introduced.<ref name="constexpr-containers"/>

A proposal for <code>constexpr</code> coroutines was published in 2025 by Hana Dusíková for adoption to C++26, but was delayed to C++29.<ref>{{Cite web|title=constexpr coroutines|url=https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3367r4.html|publisher=WG21|author=Hana Dusíková|date=17 February 2025|website=open-std.org}}</ref>

== <code>consteval</code> == {{Main|Compile-time function execution}} '''{{mono|consteval}}''' is a function specifier that specifies the function to be an "immediate function"<ref name="immediate-functions"/>, i.e. that every call of the function must produce a compile-time constant expression. In other words, the function may only be executed at compile time.{{refn|name="cppref_consteval"}} If the compiler cannot evaluate the call at compile time, the program fails to compile.{{refn|name="cppstories"| {{cite web |author=<!-- not stated --> |date=28 November 2022 |title=const vs constexpr vs consteval vs constinit in C++20 |url=https://www.cppstories.com/2022/const-options-cpp20/ |website=cppstories.com. |location= |publisher= |access-date= 3 May 2026 }} }} <code>consteval</code> is also used for <code>if consteval</code> blocks.<ref name="cppreference-if"/> <syntaxhighlight lang="cpp"> import std;

using std::array;

consteval int square(int x) { return x * x; }

template <size_t N> consteval array<int, N> squaresUpTo() { array<int, N> squares; for (size_t i = 0; i < N; ++i) { squares[i] = square(i); } return squares; }

int main() { constexpr int a = square(5); // OK: evaluated at compile time

// OK: evaluated at compile time because square() is consteval int b = square(5); constexpr array<int, 5> table = squaresUpTo<5>(); int x = 3; // NOT OK: x is not a constant expression // int y = square(x); } </syntaxhighlight>

== <code>constinit</code> == '''{{mono|constinit}}''' is a variable specifier that guarantees static initialization, with static/global or thread-storage (<code>thread_local</code>) duration, and requires initialization with a constant expression. <code>constinit</code> produces a compilation error if used on a local variable or if it fails to initialize at compile-time.{{refn|name="cppref_constinit"}} <code>constinit</code> does not imply immutability, and can thus be seen a mutable compile-time variable.{{refn|name="cppstories"}} <code>constinit</code> may not be used together with <code>constexpr</code>, but when the declared variable is a reference, it is equivalent to <code>constexpr</code>. <code>constinit</code> does not mandate constant destruction or <code>const</code>-qualification, allowing objects with <code>constexpr</code> constructors but non-<code>constexpr</code> destructor.

<syntaxhighlight lang="cpp"> const char* g() { return "Dynamic initialization"; }

constexpr const char* f(bool b) { return b ? "Constant initializer" : g(); }

// OK: initialized at compile-time constinit const char* s1 = f(true);

// NOT OK: g() not constant expression // constinit const char* s2 = f(false); </syntaxhighlight>

<code>constinit</code> is used to prevent the so-called "static initialization order fiasco", where global (or static) objects in different translation units are initialized in an unspecified order.<ref name="adding-constinit"/>

== In other languages == Equivalents of <code>constexpr</code> in other languages include <code>const</code> in C#<ref>{{Cite web|title=The const keyword|url=https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/const|publisher=Microsoft Learn|author=Microsoft Learn|website=learn.microsoft.com|date=26 January 2026}}</ref> and Rust<ref>{{Cite web|title=Keyword const|url=https://doc.rust-lang.org/std/keyword.const.html|author=Rust Language Foundation|publisher=Rust Language Foundation|website=doc.rust-lang.org|date=25 March 2026}}</ref> which declare a symbol to be compile-time. Rust additionally has <code>const fn</code>, equivalent to a <code>constexpr</code> function in C++.<ref>{{Cite web|title=The Rust Reference - Constant evaluation|url=https://doc.rust-lang.org/reference/const_eval.html|publisher=Rust Language Foundation|author=Rust Language Foundation|date=30 April 2026|website=doc-rust.lang.org}}</ref> <code>const</code> in Go allows for compile-time constants, but not functions.<ref>{{Cite web|title=Constants|url=https://go.dev/blog/constants|author=Rob Pike|date=25 August 2014|website=go.dev|publisher=The Go Blog}}</ref> Zig features a <code>comptime</code> keyword to force code to be executed at compile time.<ref>{{Cite web|title=Comptime|url=https://zig.guide/language-basics/comptime/|date=4 January 2026|author=zig.guide|website=zig.guide|publisher=Zig Software Foundation}}</ref>

A Java library, <code>net.onedaybeard.constexpr</code>, features an annotation <syntaxhighlight lang="java" inline>@ConstExpr</syntaxhighlight> which simulates <code>constexpr</code> from C++ in Java.<ref>{{Cite web|title=junkdog/constexpr-java|url=https://github.com/junkdog/constexpr-java|author=Adrian Papari|website=github.com|publisher=junkdog|access-date=14 April 2026}}</ref> Meanwhile, a variable being declared with <code>static final</code> and of either primitive type or <code>java.lang.String</code> is considered a constant expression.<ref>{{Cite web|title=Chapter 15. Expressions - 15.28. Constant Expressions|url=https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.28|author=Oracle Corporation|publisher=Java Language Specification|website=docs.oracle.com|access-date=14 April 2026}}</ref>

== See also == * Const (computer programming) * Compile-time function execution

== References == {{Reflist}} {{C programming language}} {{C++ programming language}}

Category:C (programming language) Category:C++ Category:Variable (computer science)