If and else chain decisions together in C++ by evaluating a boolean condition and running the branch that matches it. Add an [[else]] and the compiler guarantees one of the two paths runs, which is what makes a branch safe when a value has to be produced. Chain several conditions with [[else if]] and you have a decision ladder that reads almost like a table of rules.
What an if statement actually does
An if statement evaluates a condition. If the condition is true, the statement or block that follows runs. If it is false, the whole thing is skipped.
#include
int main() {
int pizzas_ordered = 3;
int free_pizza_threshold = 5;
if (pizzas_ordered >= free_pizza_threshold) {
std::cout << "You qualify for a free pizza!\n";
}
std::cout << "Order recorded: " << pizzas_ordered << " pizzas\n";
return 0;
}The condition between the parentheses must be convertible to bool. An int works because zero is false and anything non-zero is true, but a floating-point comparison is a different matter — see below.
The if / else pair
An else clause covers the case where the condition was false. Together the two form a complete decision: exactly one of them runs, always.
#include
int main() {
int cheese_toppings = 2;
if (cheese_toppings >= 3) {
std::cout << "Supreme pizza: extra cheese included\n";
} else {
std::cout << "Standard pizza: no extra cheese\n";
}
return 0;
}This matters more than it looks. If a value has to end up set, the if / else pair forces you to deal with the alternative. A bare if lets the value fall through unset, and the compiler will not complain.
Building a ladder with else if
An else if chain tests a series of conditions in order. The first one that matches wins, and the rest are skipped entirely, so the order of the tests changes the meaning of the program.
#include
int main() {
int size_in_inches = 14;
if (size_in_inches <= 10) {
std::cout << "Size: small (10 inch)\n";
} else if (size_in_inches <= 14) {
std::cout << "Size: medium (14 inch)\n";
} else if (size_in_inches <= 18) {
std::cout << "Size: large (18 inch)\n";
} else {
std::cout << "Size: party (22 inch)\n";
}
return 0;
}Order the tests from most specific to least and the ladder behaves like a lookup table. Order them the other way round and the first clause swallows everything below it — a 10-inch pizza tested against the "large" clause would be reported as large.
The condition must be a boolean expression
A common beginner error is writing a comparison that is accidentally always true.
#include
int main() {
int extra_cheese = 1;
if ((extra_cheese = 1)) { // assignment, not comparison!
std::cout << "Assignment in a condition: always true\n";
}
if (extra_cheese) {
std::cout << "A non-zero int is treated as true\n";
}
return 0;
}The first line assigns 1 to extra_cheese and evaluates to the assigned value, which is true. The extra parentheses around the assignment silence the compiler's warning, which is a hint that the code is doing something unusual; remove them and -Wall points straight at the mistake. The fix is to use == instead.
Another trap involves floating point. Comparing total == 10.0 fails for values that are mathematically equal but differ in their last bits, so range checks like total > 9.99 && total < 10.01 are usually safer.
The dangling else problem
When you leave the braces off, the else attaches to the nearest unmatched if. That is often not the pairing you intended.
if (member)
if (discount == 0)
discount = 5;
else
discount = 10;The else here belongs to the *inner* if, so when member is true but discount is not zero, the discount becomes 10 rather than 5. Most people read the indentation and assume the else belongs to the outer test. Compilers warn about this with the -Wdangling-else option, and the warning is worth reading rather than suppressing.
Writing the braces explicitly removes the ambiguity for good:
#include
int main() {
bool member = true;
int discount = 0;
if (member) {
if (discount == 0) {
discount = 5;
} else {
discount = 10;
}
}
std::cout << "discount: " << discount << '\n';
return 0;
}The rule is simple: always use braces, even around a single statement.
Branching that always produces a value
A function whose branches all assign to a result variable is easy to reason about and easy to extend.
#include
int price_for_size(int inches) {
int price = 0;
if (inches <= 10) {
price = 899;
} else if (inches <= 14) {
price = 1299;
} else if (inches <= 18) {
price = 1699;
} else {
price = 2299;
}
return price;
}
int main() {
std::cout << "10 inch: " << price_for_size(10) << "\n";
std::cout << "16 inch: " << price_for_size(16) << "\n";
std::cout << "24 inch: " << price_for_size(24) << "\n";
return 0;
}The output shows each size landing in the expected bracket:
10 inch: 899
16 inch: 1699
24 inch: 2299Notice that the middle size, 16 inches, skipped the 14-inch bracket because the 14-inch test failed first.
Quick reference
- An
ifruns its branch only when the condition is true; anelsecovers the rest. if / elseguarantees exactly one branch runs, so a value in each branch is always set.- In an
else ifchain the first matching condition wins, so order the tests from specific to general. - Use
==for comparison; a single=assigns and the condition becomes always true. - Always use braces, or the
elsebinds to the wrongif. - Keep floating-point comparisons out of exact equality tests.
- Compile with
-Wallto catch assignment-in-condition mistakes.
Try it yourself: write a pizza pricing ladder with four size brackets and a chain of extra-topping prices. Then break the braces on purpose and watch how the [[else]] re-binds. Finally, add an "unknown size" case that returns a fallback price and confirm every path through the function produces a sensible number.