{{short description|C/C++ specifier referring to constant expression}} {{lowercase title}} '''{{mono|constexpr}}''' is a specifier keyword in the [[C (programming language)|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 [[Const (computer programming)|{{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 [[C preprocessor|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 type|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 [[reflective programming|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 (C standard revision)|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 (high-level programming language)|variable]] or a [[Template (C++)#Variable templates|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 [[Const (computer programming)|{{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> [[C++17|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 [[Record (computer science)|aggregate types]] (i.e. [[Struct (C programming language)|structs]]), [[array (data structure)|arrays]], and [[Product type|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, [[Pointer (computer programming)|pointers]] (except [[Null pointer|<code>nullptr</code>]]), variably modified types, [[atomic type]]s and [[Volatile (computer programming)|{{mono|volatile}}]] types may not be <code>constexpr</code>.
In C++, <code>constexpr</code> pointers and [[reference (C++)|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 (data type)|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 [[inline (C and C++)|{{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>
[[Coroutine]]s 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 assembler|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 (programming)|closure types]] and lambda functions to be used in constant evaluation content.<ref name="cppref_constexpr"/>
[[Method (computer programming)|Class methods]] and [[operator overloading|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 function]]s 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 (computer programming)|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 (computer programming)|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 [[Reflective programming|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 [[C++ Standard Library|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 [[class variable|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 [[static (keyword)|{{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 [[Recursion (computer science)|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 statement]]s, [[control flow]] blocks such as <code>if</code>/<code>else</code> and <code>switch</code>, [[loop (computing)|loops]], and [[variable (computer programming)|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 [[Inline (C and C++)|{{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 function (computer programming)|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 allocation]]s 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 function|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 variable]]s, 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 syntax|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> [[coroutine]]s 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 [[Compile-time function execution|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 (programming)|initialization]], with [[Static variable|static]]/[[global variable|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 (C++)|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 Sharp (programming language)|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 (programming language)|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 (programming language)|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 (programming language)|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 (programming language)|Java]] library, <code>net.onedaybeard.constexpr</code>, features an [[Java annotation|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)]]