Conditionals (if / switch)
if/else branch on a boolean; switch does a multi-way jump on an integral or enum value, often compiled to a jump table for O(1) dispatch.
Why it matters
switch on a dense set of cases lowers to a jump table — constant-time regardless of case count — whereas a chain of ifs is linear; for hot dispatch (bytecode interpreters, state machines) this is measurable. C++17’s init-statement (if (auto x = f(); cond)) scopes a variable to the branch, a clean pattern for lock guards, std::optional unwrapping, and error checks.
How it works
if (init; cond)andswitch (init; cond)(C++17) declare a variable visible only inside the statement and itselse— tighter scope, fewer leaks into the enclosing block.if constexpr(C++17) discards the untaken branch at compile time — essential in templates to avoid instantiating invalid code.switchrequires integral/enum/constexpr-convertible conditions; non-matching falls todefaultif present.[[likely]]/[[unlikely]](C++20) hint the branch predictor for codegen.
| Construct | Dispatch | Compile-time | Typical use |
|---|---|---|---|
if/else if | linear | no | few, complex conditions |
switch | jump table | no | dense integral cases |
if constexpr | none | yes | template branch pruning |
Example
if (auto it = cache.find(key); it != cache.end())
return it->second; // it scoped to the if/else only
switch (token.kind) {
case Plus: emit_add(); break; // break: no fall-through
case Minus: emit_sub(); break;
default: error(); // catch-all
}
template <class T> void f(T v) {
if constexpr (std::is_pointer_v<T>) use(*v); // other branch never compiled
else use(v);
}Pitfalls
- Missing
breakfalls through to the next case — sometimes intended (mark with[[fallthrough]];), usually a bug. - Declaring a variable in a
casewithout braces can skip its initialization; wrap the case body in{ }. if (x = 5)assigns then tests truthiness — meant==. Enable-Wparentheses; or writeif (5 == x).- Runtime
if, notif constexpr, on a type trait still compiles both branches and fails on the invalid one.