Constexpr
constexpr is a specifier keyword in the C and C++ programming languages which, roughly speaking, specifies that something may be evaluated at compile time. Unlike the usual const, which specifies read-only access, constexpr is a stronger form that often implies const. While in C this is limited only to objects, constexpr may be used on objects, functions, or structured bindings in C++.
constexpr is a specifier keyword in the C and C++ programming languages which, roughly speaking, specifies that something may be evaluated at compile time.[1] Unlike the usual const, which specifies read-only access, constexpr is a stronger form that often implies const. While in C this is limited only to objects,[2] constexpr may be used on objects, functions, or structured bindings in C++.[1]
History
[edit]The word constexpr is a portmanteau of constant expression[3], first introduced in C++11. Prior to the introduction of constexpr, options for specifying compile-time constants and functions in C++ were limited to preprocessor macros (such as #define PI 3.1415926535 or procedural macors like #define SQUARE(x) ((x) * (x))), which performed textual substitution and thus lacked the type safety of a core language feature, or declaring an enumerated constant (such as enum { WINDOW_SIZE = 600 };), which was limited only to integral types. A particular motivation for the development of compile-time expressions was that std::numeric_limits<T>::max(), although equivalent to the macro INT_MAX, produced a non-constant expression.[4] Compile-time expressions were first proposed for inclusion into C++ by Gabriel Dos Reis in 2003[5], 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.[4] This proposed was further revised with the co-authorship of Bjarne Stroustrup and Jens Maurer in 2006 to introduce the constexpr keyword, along with including user-defined literals (objects of user-defined types with constexpr constructors and destructors) into the definition of constant expressions.[4], and adopted into the draft for C++11 in July 2007.[6].
constexpr was later introduced into C, beginning in C23.[2][7]
Semantics
[edit]The primary usage of constexpr is to allow for evaluating complex calculations at compile time, avoiding runtime overhead such as additional stack frames or memory[3] without relying on preprocessor directives, as well as preventing certain cases of undefined behavior.[8]
Variables
[edit]A variable or a variable template may be declared constexpr if it is a definition, is a literal type, is initialized at declaration, and is constant-initializable.[9] Such a constexpr variable is implicitly made const. References may also be made constexpr provided they are initialized by constant expression and any implicit conversions invoked during initialization are also constant expressions.[3]
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;
constexpr variables may not refer to entities local to a translation unit, such as entities not exported from a module.
In C, pointers (except nullptr), variably modified types, atomic types, volatile types, and restrict pointers may not be constexpr.
Functions
[edit]A constexpr function is a function whose return value may be computed at compile time (i.e. when when the arguments are constant expressions), and when called at runtime, behaves as a regular function.[3] A constexpr function evaluated at compile time will halt compilation once undefined behavior is invoked.[8]
constexpr double div(double a, double b) noexcept {
return a / b;
}
double x = div(1, 0); // Prevents compilation, due to invoking undefined behavior
Because the return types of constexpr functions may be known at compile time, they may be invoked at compile time for use in compile-time expressions.
constexpr int getFive() noexcept {
return 5;
}
int numbers[getFive() + 7]; // Creates an array of 12 ints
Coroutines may not be constexpr, however a C++29 proposal exists for constexpr coroutines.[10] Historically, constexpr functions had far more restrictions, including the disallowing of multiple return statements, try blocks, and inline assembly blocks, all of which have been gradually relaxed with each revision.[1][11]
Class methods may also be declared with constexpr. Prior to C++14, constexpr methods had const access, preventing them from being able to manipulate the class.[3] Prior to C++20, virtual functions could not be constexpr.[1][12]
Constructors and destructors
[edit]A constexpr constructor is one such that it allows the class to be initialized and declared at compile time. Until C++26, classes with virtual base classes could not have constexpr constructors. The introduction of constexpr virtual inheritance seeks eventually allowing for constexpr stream formatting through a constexpr constructor for std::ios_base.[13] The implicitly generated constructor is guaranteed to be constexpr if the class is a literal type.[14][15]
A constexpr destructor (introduced in C++20), meanwhile, is a destructor allowing destruction of the object at compile time. The primary motivations for the introduction of constexpr destructors were for allowing the usage of non-trivial classes at compile-time, such as std::string and std::vector, the latter of which is used extensively in the API of std::meta's compile-time reflection.[16] The implicitly generated destructor is guaranteed to be constexpr if the class is a literal type.[17] Like constexpr constructors, constexpr destructors historically disallowed destruction of classes with virtual base classes. In C++26, various standard library classes, which have been historically runtime-only, have been made compile-time eligible through constexpr destructors.[18]
A class with static members that are instances of itself may be constexpr, but the fields inside the class must first be declared const while the constexpr declarations must reside outside the class.
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} {}
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);
Compile-time if statements
[edit]C++ features two forms of compile-time if statements: if constexpr and if consteval.[19]
The former, if constexpr, introduced in C++17, allows for conditional branching at compile time. It requires that the condition be a constant expression convertible to bool.[19] if constexpr 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.[20] return statements in a discarded statement do not participate in function return type deduction.
import std;
using std::is_pointer_v;
// The deduced return type can be spelled out in full as
// conditional_t<is_pointer_v<T>, remove_pointer_t<T>, T>
template <typename T>
constexpr auto getValue(T t) noexcept {
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 a;
}
The latter, if consteval, introduced in C++23, acts as a if constexpr where the condition is whether or not the if condition is being evaluated at compile time, rather than at runtime.[21]
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];
}
}
if consteval introduces an additional syntax: if !consteval { /* stmt1 */ } else { /* stmt2 */ } is equivalent to if consteval { /* stmt2 */ } else { /* stmt1 */ }[19]
In other languages
[edit]Equivalents of constexpr in other languages include const in C#[22] and Rust[23] which declare a symbol to be compile-time. const in Go allows for compile-time constants, but not functions.[24] Zig features a comptime keyword to force code to be executed at compile time.[25]
A Java library, net.onedaybeard.constexpr, features an annotation @ConstExpr which simulates constexpr from C++ in Java.[26] Meanwhile, a variable being declared with static final and of either primitive type or java.lang.String is considered a constant expression.[27]
See also
[edit]References
[edit]- ^ a b c d cppreference.com. "constexpr specifier (since C++11)". cppreference.com. cppreference.com. Retrieved 14 April 2026.
- ^ a b cppreference.com. "constexpr specifier (since C23)". cppreference.com. cppreference.com. Retrieved 14 April 2026.
- ^ a b c d e Microsoft Learn (22 February 2023). "constexpr (C++)". learn.microsoft.com. Microsoft Learn.
- ^ a b c Gabriel Dos Reis, Bjarne Stroustrup, Jens Maurer (3 November 2006). "Generalized Constant Expressions - Revision 5" (PDF). open-std.org.
{{cite web}}: CS1 maint: multiple names: authors list (link) - ^ Gabriel Dos Reis (21 September 2003). "Generalized Constant Expressions" (PDF). open-std.org. WG21.
- ^ Herb Sutter (21 June 2025). "Trip report: June 2025 ISO C++ standards meeting (Sofia, Bulgaria)". herbsutter.com. Herb Sutter.
- ^ Alex Gilding, Jens Gustedt (6 July 2022). "The constexpr specifier for object definitions". open-std.org. WG14.
- ^ a b WG21. "7 - Expressions, 7.7 - Constant expressions". eel.is. WG21. Retrieved 14 April 2026.
{{cite web}}: CS1 maint: numeric names: authors list (link) - ^ cppreference.com. "Constant expressions - Constant initialized entities". cppreference.com. cppreference.com. Retrieved 14 April 2026.
- ^ Hana Dusíková (17 February 2025). "constexpr coroutines". open-std.org. WG21.
- ^ Richard Smith (15 March 2013). "Relaxing constraints on constexpr functions". WG21.
- ^ Peter Dimov, Vassil Vassilev (4 May 2018). "Allowing Virtual Functions Calls in Constant Expressions". open-std.org. WG21.
- ^ Hana Dusíková (17 February 2025). "constexpr virtual inheritance". open-std.org. WG21.
- ^ cppreference.com. "Default constructors". cppreference.com. cppreference.com. Retrieved 14 April 2026.
- ^ cppreference.com (14 April 2026). "Constant expressions - Literal type". cppreference.com. cppreference.com.
- ^ Wyatt Childers; et al. (26 June 2024). "P2996R4 - Reflection for C++26". isocpp.org. WG21.
- ^ cppreference.com. "Destructors". cppreference.com. cppreference.com. Retrieved 14 April 2026.
- ^ Hana Dusíková (11 February 2025). "constexpr containers and adaptors". open-std.org. WG21.
- ^ a b c cppreference.com. "if statement". cppreference.com. cppreference.com. Retrieved 14 April 2026.
- ^ Jens Maurer (20 June 2016). "P0292R2: constexpr if: A slightly different syntax". open-std.org. WG21.
- ^ Barry Revzin, Richard Smith, Andrew Sutton, Daveed Vandevoorde (22 March 2021). "if consteval". open-std.org. WG21.
{{cite web}}: CS1 maint: multiple names: authors list (link) - ^ Microsoft Learn (26 January 2026). "The const keyword". learn.microsoft.com. Microsoft Learn.
- ^ Rust Language Foundation (25 March 2026). "Keyword const". doc.rust-lang.org. Rust Language Foundation.
- ^ Rob Pike (25 August 2014). "Constants". go.dev. The Go Blog.
- ^ zig.guide (4 January 2026). "Comptime". zig.guide. Zig Software Foundation.
- ^ Adrian Papari. "junkdog/constexpr-java". github.com. junkdog. Retrieved 14 April 2026.
- ^ Oracle Corporation. "Chapter 15. Expressions - 15.28. Constant Expressions". docs.oracle.com. Java Language Specification. Retrieved 14 April 2026.