Language[lang]

constexpr in C++: variables, functions and static constexpr

Section
Language [lang]
Standard
C++17
Compilers
MSVC 19.44, Clang 19.1 (MSVC STL), GCC 16.2, Clang 23.1 (libc++)
Published
Length
7 min read
In this answer8 clauses
  1. 1What is a constexpr variable?
  2. 2constexpr vs const: what is the difference?
  3. 3Is a constexpr function evaluated at compile time?
  4. 4What can a constexpr function contain?
  5. 5What is static constexpr in a class?
  6. 6What is inline constexpr in a header?
  7. 7What are consteval and constinit?
  8. 8const, constexpr, static constexpr or inline constexpr: which should you write?

Abstract

constexpr in C++ marks a variable or function that can be computed while the program is compiled. A constexpr variable is a constant the compiler knows; a constexpr function runs in the compiler when its arguments are constants and the result is needed there, and at run time when its arguments are known only then. Write const for a value fixed at run time, constexpr for a compile-time constant, static constexpr for a class’s constant and inline constexpr (C++17) for a constant in a header.

A dotted line splits the drawing. Left: two hatched cells join at a node whose arrow drops a blue cell into a row of cells. Right: the same row, blue cell in place, the calculation greyed out.
Figure 1 — The compiler computes a constexpr value while it builds the program, so the value is ready before the program runs.

constexpr in C++ marks a variable or a function whose value can be computed while the program is compiled. A constexpr variable is a constant the compiler must know, so it can size an array. A constexpr function can be run by the compiler when its arguments are constants, and runs like any other function when they are not.

The smallest whole program uses both, for a game of up to four players:

[Example 1:
#include <iostream>
#include <iterator>

constexpr int max_players = 4;          // known while compiling

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

int main(int argc, char*[]) {
    int scores[max_players] = {};       // OK: an array size
    static_assert(square(12) == 144);   // computed by the compiler

    int n = argc + 6;                   // known only while running: 7
    std::cout << "slots: " << std::size(scores) << '\n';
    std::cout << "square(n): " << square(n) << '\n';
}

— end example]

It printed:

[Example 2:
slots: 4
square(n): 49

— end example]

A static_assert is a check the compiler makes: if it is false, the build stops. This one passed, so square(12) was computed while compiling. square(n) ran at run time, because n comes from argc, the count of command-line arguments, known only once the program starts.

The samples on this page are C++17, and C++20 where a comment says so, built with MSVC 19.44, Clang 19.1 (MSVC STL), GCC 16.2 and Clang 23.1 (libc++); all four agreed on every one shown. Since When lists the compiler releases that added each feature.

What is a constexpr variable?

A constexpr variable is a constant whose value the compiler knows: it must be initialized where it is declared, by an expression the compiler can compute. That is what lets it size an array or be a template argument:

[Example 3:
constexpr int max_players = 4;
constexpr int seconds_per_day = 24 * 60 * 60;  // done by the compiler

int scores[max_players];                 // a built-in array's size
std::array<int, max_players> lives{};    // a template argument

static_assert(seconds_per_day == 86400);
static_assert(std::is_const_v<decltype(max_players)>);  // it is const

— end example]

Initialize one from a value the compiler cannot know, and the build fails:

[Example 4:
int n = 5;
constexpr int doubled = n * 2;  // error: n is not a constant

— end example]

n holds 5, but it is an ordinary variable, not a constant. Clang said constexpr variable 'doubled' must be initialized by a constant expression.

constexpr vs const: what is the difference?

const promises that a value will not change once it is set, and that value may be computed while the program runs; constexpr promises that the compiler knows the value. Every constexpr variable is const ([dcl.constexpr]), but not every const variable is a compile-time constant.

const int limit = read_setting();, where read_setting is an ordinary function, compiles and is fixed from then on, but it is not a compile-time constant. A const int set from a constant, such as const int rows = 3;, is one: the language makes that exception for const integers, and rows sized an array as well as constexpr int cols = 4; did.

Using limit as an array size is not standard C++: MSVC rejected it, Clang accepted it with a warning that calls it an extension, and GCC accepted it without a warning at -Wall -Wextra. constexpr is what guarantees the value is known while compiling.

What const does on pointers, references and member functions is in const in C++.

Is a constexpr function evaluated at compile time?

Yes, when its arguments are constants and the result is needed while compiling: in a constexpr variable, an array size or a static_assert. Called with a value known only while running, it runs like any other C++ function, so one function serves both:

[Example 5:
constexpr int factorial(int n) {
    int result = 1;
    for (int i = 2; i <= n; ++i)
        result *= i;
    return result;
}
// ...
static_assert(factorial(5) == 120);   // done by the compiler
int seatings[factorial(4)] = {};      // 24 ways to seat 4 players

int n = argc + 5;                     // known only now: 6
std::cout << "seatings: " << std::size(seatings) << '\n';
std::cout << "factorial(n): " << factorial(n) << '\n';

— end example]

All four printed seatings: 24 and factorial(n): 720.

Two lanes: while compiling, while running. Left: static_assert(square(12) == 144) calls the box square(x); 12 is a constant, so the compiler computes 144. Right: square(n) calls the same box; n is known only now: an ordinary call.
Figure 2 — One constexpr function, two uses: the compiler computes it when its arguments are constants and the result is needed while compiling; with an argument known only while running, the program calls it like any other function.

Demand a compile-time result from a run-time value, and the build fails:

[Example 6:
constexpr int big = factorial(argc);  // error: argc is not known

— end example]

Clang’s note names the cause: function parameter 'argc' with unknown value cannot be used in a constant expression.

What can a constexpr function contain?

In C++11 the body could hold little more than one return statement. Since C++14 it may declare local variables and use loops, if and switch, as factorial does. C++20 added more, including try blocks, virtual functions and memory from the heap: since then a std::string or a std::vector can be used inside a constexpr function.

What is static constexpr in a class?

A static constexpr data member is a constant that belongs to the class, not to each object, with its value written in the class. constexpr static is the same thing in the other order:

[Example 7:
class Board {
public:
    static constexpr int size = 8;         // one for the class
    constexpr static int max_players = 4;  // the same, other order

    char cells[size][size] = {};           // sizes a member array

    int squares() const {
        return size * size;                // used inside the class
    }
};

— end example]

From outside the class it is Board::size. All four printed sizeof(Board): 64, the 64 cells alone: the constants take no room in an object. Since C++17 a static constexpr member is implicitly inline, so it needs no definition outside the class.

What is inline constexpr in a header?

A constexpr variable outside a class, in a header file, gives every source file that includes it its own copy; inline constexpr, since C++17, makes them all share one object:

[Example 8:
inline constexpr int port = 8080;  // one object in the program
constexpr int retries = 3;         // one object per source file

— end example]

In a program of two source files that compared the addresses they saw, all four printed one port: true and one retries: false. An inline variable can be defined in every file that includes it and still be one object, so write the constants in a header as inline constexpr. A constexpr function needs no inline there: it is implicitly inline, so define it whole in the header.

What are consteval and constinit?

Both are C++20. A consteval function must run in the compiler, and constinit makes sure a global variable gets its value while compiling, but leaves it changeable:

[Example 9:
consteval int cube(int x) {            // C++20: only in the compiler
    return x * x * x;
}

constinit int counter = cube(2);       // C++20: set while compiling

int main() {
    constexpr int volume = cube(3);    // a constant argument: OK
    std::cout << "volume: " << volume << '\n';

    counter += 1;                      // constinit is not const
    std::cout << "counter: " << counter << '\n';
}

— end example]

Built as C++20, all four printed volume: 27 and counter: 9. Called with a run-time n, cube(n) was rejected by all four; GCC said call to consteval function 'cube(n)' is not a constant expression.

const, constexpr, static constexpr or inline constexpr: which should you write?

You need Write
A value fixed once, known only when the program runs const
A constant the compiler must know, in a function or a source file constexpr
A constant that belongs to a class static constexpr
A constant in a header inline constexpr (C++17)
A function usable both while compiling and while running constexpr
A function that must never run at run time consteval (C++20)

The rest of the core language is in Language.

Questions

What is the difference between constexpr and const?

const means a value does not change once it is set, and that value may be computed while the program runs, for example from a function’s result. constexpr means the compiler knows the value, so it can size an array or appear in a static_assert. Every constexpr variable is also const, but not every const variable is a compile-time constant.

What is static constexpr?

In a class, static constexpr declares a constant that belongs to the class rather than to each object, with its value written inside the class, such as static constexpr int size = 8;. Inside a function, static constexpr makes one constant that lasts for the whole program, rather than one for each call. constexpr static means the same thing: the order of the two words does not matter. Since C++17 a static constexpr member needs no definition outside the class.

Can a std::string be constexpr?

Only partly, so do not rely on it. Built as C++20, constexpr std::string name = “Ana”; outside any function compiled on all four compilers tried, a 32-character text compiled on none (the messages point at memory from the heap), and the short one inside a function failed with GCC’s library. For a constant text, use constexpr std::string_view or a const char array; a std::string can be used inside a constexpr function since C++20.

Is there constexpr in C?

Yes, since C23, for objects only: constexpr int limit = 5; declares a constant, but a constexpr function is not allowed. Clang and GCC compiled it as C23; MSVC 19.44 did not support it.

What is if constexpr?

if constexpr is a different feature, since C++17: an if statement whose condition the compiler decides while compiling. It is used mostly in templates.

Does constexpr make code faster?

Not by itself. A value computed while compiling, such as a constexpr variable’s, is not computed again while the program runs. A constexpr function called with values known only at run time runs like any other function.

Sources

  1. constexpr specifiercppreference.com
  2. [dcl.constexpr] The constexpr and consteval specifiersC++ standard working draft
  3. consteval specifiercppreference.com
  4. constinit specifiercppreference.com
  5. inline specifiercppreference.com
  6. Static memberscppreference.com
  7. constexpr specifier (since C23)cppreference.com
  8. std::basic_stringcppreference.com

Read next

  1. C++ function pointer: syntax, callbacks and examplesLanguage · Miriam Castellanos · written for C++17
  2. C++ main function: int main(), argc and argvLanguage · Miriam Castellanos · written for C++17
  3. const in C++: variables, pointers, references, methodsLanguage · Miriam Castellanos · written for C++17