compile timerun time1constexpr int sq(int n) {2 return n * n;3}4int main(int argc, char**) {5 constexpr int N = sq(4);6 static_assert(N == 16);7 int buf[N] = {};8 const int k = argc * 3;9 return sq(k) + buf[0];10}N = 16$ _k3CPU0000000000000000sq(4)N==16argc16ok1359!
Violet card and tokens: the code (sq(4), N==16, argc)Back zone: compile time (sand compiler, plum program file); front zone: run time (terminal, blue memory, CPU)Khaki tokens: values; red !: a compile errorLeft: the code card app.cpp. Right: two zones. At the back, compile time: the compiler and the program file it writes. In front, run time: the terminal, k's box (locked: const), the CPU and the array buf. constexpr values are worked out by the compiler: sq(4) goes in, 16 comes out and is baked into the program, and it sizes buf. const k is set once at run time from argc, then never changes; the same sq runs again on the CPU. Red tokens mark the two compile errors: writing to a const, and building a constexpr from a run-time value. The program on the card is real, standard C++20. It compiles with no warnings under g++ or clang++ -std=c++20 -Wall -Wextra; ./app exits with status 9 and ./app a b with 81.

Compile time

  1. A C++ program has two lives: compile time, while the compiler builds it, and run time, while the CPU runs it. constexpr in front of sq means the compiler may run sq itself, during the build.

Run time

Choosing

What happens

;; step 1/11 · constexpr-fn
line 1   constexpr int sq(int n) {
line 2     return n * n;
constexpr   'can be evaluated at compile time'
compile time   the compiler builds app from app.cpp
run time       the CPU runs app

Compile time and run time: the compiler (g++ or clang++) turns app.cpp into the program file app; running ./app happens later, as often as you like. Values a program reads when it runs, such as argc or user input, cannot be known while it is built. The standard guarantees that N's value is known to the compiler, so it can be used where a constant expression is required. Whether N also gets a slot in memory is up to the compiler; in practice 16 is written into the machine code wherever N is used.