C++ PROGRAMMING ยท 11 MIN STUDY

constexpr and compile-time programming

Understand constexpr evaluation, consteval, constinit, and static_assert with practical examples.

Learning objectives

  • Distinguish const objects from constant expressions.
  • Write a constexpr function usable at compile time and runtime.
  • Understand consteval and constinit.
  • Use static_assert to check assumptions at compile time.

Prerequisites: functions, constants, templates, and basic type deduction. Review Functions, Constants, and Templates first. The examples distinguish C++11, C++17, and C++20 facilities.

Language versions: constexpr and static_assert are available from C++11; C++14 relaxed the rules for constexpr function bodies. The message-free form of static_assert used below requires C++17. consteval and constinit are C++20 features.

const is not the same as constexpr

const means an object cannot be modified through that name after initialization. constexpr says a variable or function can participate in constant evaluation when the rules and arguments permit it.

constexpr int square(int value) {
    return value * value;
}
constexpr int answer = square(6); // evaluated at compile time
int runtime_value = 7;
int result = square(runtime_value); // evaluated at runtime

A constexpr function is not forced to run at compile time on every call. It can also execute at runtime when given runtime values.

Compile-time checks with static_assert

static_assert(sizeof(int) >= 2, "int must be at least 2 bytes");
static_assert(square(4) == 16);

If the condition is false, compilation fails. Use this for assumptions that must be true for the program to be valid.

consteval: must be compile time

consteval int triple(int value) {
    return value * 3;
}
constexpr int fixed = triple(5); // valid
// int x = triple(runtime_value); // invalid

A consteval function is an immediate function: calls must be constant-evaluated. This is stricter than constexpr.

constinit: static initialization guarantee

constinit int global_counter = 0;
// global_counter is not const; it may change at runtime

constinit applies to variables with static or thread storage duration and requires static initialization. It does not make the variable immutable, and it is not a general replacement for constexpr.

When to use each

KeywordMain meaning
constNot modifiable through this name
constexprCan be used in constant expressions when possible
constevalCalls must be evaluated at compile time
constinitStatic/thread variable must be statically initialized
static_assertCompile-time condition check

Common mistakes

  • Assuming every constexpr function call is compile-time.
  • Assuming constinit makes an object const.
  • Passing runtime data to a consteval function.
  • Using static_assert for a condition that is only known at runtime.

Practice

  1. Write a constexpr function that returns the larger of two integers.
  2. Use static_assert to check its result for known inputs.
  3. Explain why a constinit variable can still be modified.
Show solutions
  1. Define constexpr int larger(int a, int b) { return a > b ? a : b; }. It returns the greater argument and can be evaluated at compile time for constant inputs.
  2. Place static_assert(larger(4, 9) == 9); after that definition. Compilation succeeds because the condition is true; changing the expected result to 8 makes compilation fail.
  3. constinit guarantees initialization timing, not immutability.

Summary

Use constexpr for values and functions that can support constant evaluation, consteval when compile-time evaluation is mandatory, constinit for static initialization guarantees, and static_assert for compile-time checks.

References