Compile-Time Evaluation with static_assert
A constexpr function is declared with the constexpr keyword so that the compiler can evaluate it at compile time.
A Function the Compiler Can Run
Most of the functions you have written so far run only when the program is running. The compiler translates your source code into a program, and each function body is executed later, when the program starts doing its work. This topic introduces a different kind of function: one that the compiler itself can evaluate while it is still translating your program.
The tool that makes this possible is a single keyword, constexpr, placed on the function declaration. Along with static_assert, which asks the compiler to check a condition during translation, it lets you have the compiler verify a value before the program ever runs. The rest of this article follows what the compiler does at each step, so you can see exactly where the keyword changes the outcome.
What the constexpr Keyword Changes
Read this declaration as a complete definition. It creates a function named square that takes one double and returns a double. The only new word is constexpr, placed before the return type. Before reading on, consider what that one keyword might change, because the answer is the central idea of this article.
What do you think happens?
Given the same body, does adding constexpr change whether a call to square can appear inside a static_assert check?
Reveal answer
Yes, constexpr makes the function eligible for constant expressions, so a call to it can be evaluated by the compiler inside a static_assert check.
The keyword does not change how the arithmetic works. It is a request that the function be eligible for compile-time evaluation, and that eligibility determines where a call may be used.
A constexpr function is a function that can be evaluated by the compiler at compile time. The keyword is a request that the function be eligible for that kind of evaluation. Its practical effect is on where the function's result may be used: a call to the function can take part in a constant expression, which is an expression the compiler itself will evaluate.
A constant expression is an expression that is evaluated by the compiler at compile time, rather than being left to run when the program executes. constexpr functions are the kind of function that can be used inside these expressions.
The Declaration Pattern
A constexpr function follows a general pattern. The keyword comes first, then the return type, the function name, the parameter list, and finally the body in braces. Each piece has a job, and you can check any declaration by naming the pieces in order.
Applying the pattern to square: constexpr marks eligibility, double is the return type, square is the name, double x is the parameter list, and the braces contain the body that returns x times x. The pattern is a template to check against, not a separate statement you write on its own.
Tracing a static_assert Check
The useful way to think about a constexpr function is as a two-part relationship. The constexpr keyword sits on the function declaration and says the function is eligible. The constant expression is the place where that eligibility is used. Neither part alone describes the whole idea. The following code puts both parts together.
- constexpr makes square eligible for constant expressions
static_assertasks the compiler to check the condition during translationsquare(3.0)is part of the condition, so the compiler must be able to evaluate it
Tracing a Failing Compile-Time Check
Suppose square is declared constexpr and the check is written as static_assert(square(3.0) == 10.0). Does the check pass?
- 1Step 1: Find the call
The compiler reaches the call
square(3.0)inside thestatic_assertcondition. - 2Step 2: Confirm eligibility
Because square is declared constexpr, the call is eligible to be evaluated by the compiler.
- 3Step 3: Compute the value
The body returns x times x, so
square(3.0)evaluates to 9.0. - 4Step 4: Compare with the expectation
The condition 9.0 == 10.0 is false.
- 5Step 5: Report the result
A false
static_assertcondition is a compile error, reported at thestatic_assertline.
The check fails at compile time. The failure is not inside the arithmetic of square; it is at the static_assert line, because that line is where the computed value is compared with the expectation.
Why constexpr Is Required
The rule is strict in one direction. For a function to be usable in a constant expression, it must be defined constexpr. Declaring a function constexpr is what makes it eligible. A plain function that happens to compute the same value does not qualify just because its body is simple.
The diagram shows only the declaration check described in the source. A function declared constexpr moves onto the path where its calls can be evaluated by the compiler. Without that declaration, the function does not qualify for constant expressions, however the call is written. The body and the call can look identical; the declaration is what decides.
Comparing Ordinary and constexpr Functions
Placing the two kinds of function side by side makes the difference easier to see. Both are ordinary-looking functions with a body that returns a value. What changes is whether a call to the function may appear in an expression that the compiler must evaluate.
The two columns are not about how the arithmetic is written. An ordinary function with the same body still runs when the program runs, and a call to it cannot take part in a constant expression. A constexpr function with that body can be evaluated by the compiler, so its call may appear inside static_assert or in another constant expression.
Mistakes With constexpr Declarations
Common mistake Assuming a simple body makes a function usable in a constant expression
What it looks likedouble square(double x) { return x * x; } followed by a static_assert that calls squareWhy it failsThe function is not declared constexpr, so it does not qualify for constant expressions, no matter how simple its body is.
Do this insteadAdd the constexpr keyword to the declaration: constexpr double square(double x) { return x * x; }Common mistake Placing constexpr after the return type
What it looks likedouble constexpr square(double x)Why it failsThe declaration pattern puts the keyword first, before the return type, name, parameter list, and body.
Do this insteadWrite constexpr double square(double x) with the keyword in the first position.
Common mistake Looking for a bug inside the function when a static_assert fails
What it looks likeRechecking the multiplication in square after static_assert(square(3.0) == 10.0) fails
Why it failsThe failure is at the
static_assertline, where the computed value is compared with the expectation. The expectation is what is wrong here, not the arithmetic.Do this insteadCompare the expected value with the computed value. square(3.0) is 9.0, so the check should use 9.0.
Common mistake Forgetting that the compiler, not the running program, evaluates a constant expression
Practice Writing a constexpr Function
Write a constexpr function named cube that takes one double and returns the cube of its input. Then write a static_assert that checks that cube(2.0) equals 8.0. Before you run the check, name each piece of your declaration in order: keyword, return type, name, parameter list, body.
Hints
- Follow the same pattern as square: constexpr, return type, name, parameter list, body in braces.
- The body can multiply the input by itself twice.
- Your
static_assertcondition should comparecube(2.0)with 8.0 using ==.
Key Takeaways
- 1A constexpr function is a function the compiler can evaluate at compile time, and the keyword makes it eligible for constant expressions.
- 2The declaration pattern puts constexpr first, then the return type, function name, parameter list, and body in braces.
- 3For a function to be usable in a constant expression, it must be declared constexpr; a simple body alone does not qualify it.
- 4A failed
static_assertis reported at thestatic_assertline, where the computed value is compared with the expected value.
At a glance
- A constexpr function is a function the compiler can evaluate at compile time, and the keyword makes it eligible for constant expressions.
- The declaration pattern is constexpr, then return type, function name, parameter list, and body in braces.
- A function must be declared constexpr before its call can appear in a constant expression, regardless of how simple its body is.
- An ordinary function and a constexpr function can have the same body, but only the constexpr one can be evaluated inside a constant expression such as
static_assert.