Conditions: if and switch
if, else and switch let a program choose what to do. C++17 added handy variations — an if with its own initialiser, and if constexpr for compile-time decisions — that keep code tidy.
if, else if, else
#include <iostream> int main() { for (int score : {95, 82, 67, 40}) { char grade; if (score >= 90) { grade = 'A'; } else if (score >= 75) { grade = 'B'; } else if (score >= 50) { grade = 'C'; } else { grade = 'F'; } std::cout << score << " -> " << grade << '\n'; } }
95 -> A 82 -> B 67 -> C 40 -> F
Conditions are checked in order and only the first true branch runs. Always use braces, even for single statements — it prevents bugs when lines are added later.
if with an initialiser
C++17 lets you declare a variable inside the if, scoped to the whole if/else chain. It keeps temporary values out of the surrounding code:
#include <iostream> #include <map> #include <string> int main() { std::map<std::string, int> stock{{"apples", 30}, {"pears", 0}}; for (std::string fruit : {"apples", "pears", "kiwis"}) { if (auto it = stock.find(fruit); it == stock.end()) { std::cout << fruit << ": not sold here\n"; } else if (it->second == 0) { std::cout << fruit << ": sold out\n"; } else { std::cout << fruit << ": " << it->second << " in stock\n"; } } }
apples: 30 in stock pears: sold out kiwis: not sold here
std::map (lesson 21) maps keys to values; find returns an iterator (lesson 23) that's end() when the key is missing.
Logical conditions
#include <iostream> int main() { int hour = 14; bool weekend = false; if (hour >= 9 && hour < 17 && !weekend) { std::cout << "Office open\n"; } int temperature = -3; if (temperature < 0 || temperature > 35) { std::cout << "Extreme temperature warning\n"; } }
Office open Extreme temperature warning
Remember that 9 <= hour < 17 doesn't mean what it looks like — write two comparisons joined with &&.
switch
switch compares one integer, character or enum value against constant cases:
#include <iostream> enum class Command { start, stop, pause, status }; void run(Command c) { switch (c) { case Command::start: std::cout << "Starting\n"; break; case Command::stop: std::cout << "Stopping\n"; break; case Command::pause: case Command::status: std::cout << "Not implemented yet\n"; break; } } int main() { run(Command::start); run(Command::status); }
Starting Not implemented yet
Without break, execution falls through into the next case — useful for grouping cases, a bug when forgotten. Mark deliberate fall-through after code with [[fallthrough]]; so compilers don't warn. When you switch on an enum class and handle every value without a default, compilers warn if a new value is added later and not handled.
#include <iostream> enum class Light { red, amber, green }; const char* action(Light l) { switch (l) { case Light::red: return "stop"; case Light::green: return "go"; } return "?"; } int main() { std::cout << action(Light::amber) << '\n'; }
main.cpp:6:13: warning: enumeration value 'amber' not handled in switch [-Wswitch]
switch with an initialiser
#include <iostream> #include <string> int main() { std::string input = "q"; switch (char c = input.empty() ? '?' : input[0]; c) { case 'q': std::cout << "quit\n"; break; case 'h': std::cout << "help\n"; break; default: std::cout << "unknown: " << c << '\n'; break; } }
quit
if constexpr
if constexpr chooses a branch at compile time and discards the other. It's mainly for templates (lesson 39), where code must adapt to different types:
#include <iostream> #include <string> #include <type_traits> template <typename T> void describe(const T& value) { if constexpr (std::is_integral_v<T>) { std::cout << value << " is an integer\n"; } else if constexpr (std::is_floating_point_v<T>) { std::cout << value << " is a floating-point number\n"; } else { std::cout << "\"" << value << "\" is something else\n"; } } int main() { describe(42); describe(2.5); describe(std::string{"text"}); }
42 is an integer 2.5 is a floating-point number "text" is something else
Try it yourself
Classify a body-mass index using if/else if.
BMI 22.7244: healthy