Visual walkthrough — Compile-time assertions — static_assert
We follow one guiding phrase the whole way down:
"If the truth is already fixed before the program runs, check it now — with a gate that costs nothing."
Step 1 — Two different clocks: build time vs run time
WHAT. Before any code, we separate two moments in a program's life that beginners blur together:
- Compile time (a.k.a. translation time): when a program called the compiler reads your text file and turns it into a machine-code file. Your program does not exist yet.
- Run time: later, when someone double-clicks that machine-code file and it actually does things.
WHY. A static_assert lives entirely in the first moment. If you don't feel the gap between these two clocks, nothing else makes sense — you'll keep expecting it to "run".
PICTURE. In the figure, one timeline. The compiler's window is on the left; the program's life is on the right. The red marker shows the only instant a static_assert is alive — before the program even boots.

Step 2 — What a "constant expression" is (the fuel)
WHAT. A constant expression is any calculation whose value the compiler can work out by itself, using only things fixed in the source: number literals, sizeof(...) results, enum values, and #defined constants. No variables you fill in later, no function calls.
WHY. The gate we're building can only ever swing on something the compiler already knows. A door can't decide to open based on a visitor who hasn't arrived. So the very first requirement is: the condition must be knowable now.
PICTURE. Two bins. On the left (red = the good fuel we can use): sizeof(int), enum COLOR_COUNT, 1024. On the right (rejected): n read from the keyboard, get_count(). An arrow shows only the left bin can flow into a static_assert.

Call this known value . Everything below is about what the compiler does with .
Step 3 — The compiler evaluates (arithmetic, not execution)
WHAT. The compiler takes your constant expression and computes its single value . For
the compiler already knows sizeof(int) is 4 here, compares 4 == 4, and gets (true).
WHY. People assume "there's arithmetic, so it must run." No — the arithmetic is done by the compiler on paper, during translation. The finished program never sees this sum.
PICTURE. A little "compiler calculator" box. The expression sizeof(int) == 4 goes in; the single number 1 (red) comes out. The output tape is labelled .

Step 4 — The gate: two doors decided by whether is zero
WHAT. Now the rule that defines static_assert. The number meets a fork:
Term by term: is the pass door — the build continues and no code is added. is the fail door — the compiler prints your "message" and halts.
WHY. We want a fail-fast at build time guard. A gate that swings on "is zero?" is exactly a truth-gate: false stops everything, true is invisible. Notice it treats any non-zero as pass (so 2, -1, 1024 all pass) — the only special value is 0.
PICTURE. The number walks toward a fork. The upper door (black, "PASS") lets the build stream through untouched. The lower door (red, "FAIL") is the emergency stop that prints the message.

Step 5 — The pass case leaves no footprint
WHAT. When , the compiler emits zero machine instructions for the assertion. It's as if you had written nothing there.
WHY. This is the whole payoff over a runtime check. A runtime assert(sizeof(int)==4) would bake a comparison into the binary and check it on every run — wasteful, since the answer can never change. static_assert spends the check once, at build, then vanishes.
PICTURE. Two binaries side by side. Left: source with a passing static_assert. Right: source without it. The compiled machine code (red bytes) is identical — the assertion left no trace.

Recall Why "zero runtime cost" matters
What does a passing static_assert add to the final binary? ::: Nothing — it emits no machine code, so the binary is byte-for-byte the same as if it weren't there.
Step 6 — The fail case: a real worked example stopping the build
WHAT. Take Worked Example 2 from the parent — keeping an array and a count in sync:
enum { COLOR_COUNT = 3 };
const char *names[] = { "red", "green", "blue", "cyan" }; // oops, 4 now
static_assert(sizeof(names)/sizeof(names[0]) == COLOR_COUNT, "out of sync");The compiler computes , compares 4 == 3, gets → FAIL door → prints out of sync and refuses to build.
WHY. This shows the gate catching a silent logic bug (someone added a colour, forgot the count) and turning it into a loud compile error — everywhere, always, before shipping.
PICTURE. The division: sizeof(names) = 4 pointers × 8 bytes = 32, over sizeof(names[0]) = 8, giving 4 (red). Then 4 == 3 → 0 → the FAIL door slams.

Step 7 — Edge cases: the doors you might not expect
WHAT. Four corner situations, each landing cleanly on the gate:
| Condition written | Door | |
|---|---|---|
static_assert(1, "...") |
PASS (trivially true) | |
static_assert(0, "...") |
FAIL (always stops the build) | |
static_assert(-1, "...") |
PASS (negative is non-zero!) | |
static_assert(sizeof(int) == 2, "...") on 32-bit |
FAIL |
WHY. These are the degenerate inputs that trip beginners. 0 is a hard stop you sometimes want (to disable a code path deliberately). -1 surprises people — but the rule is only "is it zero?", and isn't zero, so it passes.
PICTURE. A number line. Everything except the single point (all shaded red = PASS region) flows through; only the lone black dot at drops to FAIL.

The one-picture summary
Everything above is one pipeline: source text → the compiler pulls out a constant expression → reduces it to a single number → the number hits the two-door gate → pass (invisible, no code) or fail (message + stop).

Recall Feynman retelling — the whole walkthrough in plain words
Picture a bouncer at the door of a building that hasn't been built yet — that's the compiler, working before your program exists (Step 1). The bouncer only lets in facts he can already check himself: box sizes, fixed numbers, enum values — never a guest who shows up later (Step 2). He does the arithmetic in his own head on a little calculator and writes down one number, (Step 3). Then the number faces two doors: if it's anything but zero, the door opens silently and construction continues as if the check never happened (Steps 4–5). If it's exactly zero, an alarm sounds — your message is printed — and the whole building is cancelled (Steps 4, 6). The magic is that the passing check leaves no trace in the finished building (Step 5), and the only value that ever stops you is a plain 0 (Step 7). That's static_assert: a truth checked on the build-time clock, a gate that swings on zero, and a guard that costs nothing once you're done.