Control Flow
Control flow is how we get our programs to do interesting things, it allows us to write programs that do different things depending on conditions (branch) or easily repeat code (loops). C++ also has various relational and logical operators used to construct conditional expressions used by the control flow statements. You can read about them in Appendix B.
Branches
if statements
An if statement is the simplest control flow structure, it allows us to execute a piece
of code as long as a condition is true. if statements are declared using the if
keyword followed by the conditional expression in parenthesis. The code to execute is
contained in braces like function definitions.
#include <iostream>
// --snip--
auto main() -> int {
auto const x = 6;
if (x % 2 == 0) {
std::cout << "Even\n";
}
return 0;
// --snip--
}
We can add an alternative branch using the else keyword after the closing the brace of
the if the block. This branch will run if the condition in the if statement is
false.
#include <iostream>
// --snip--
auto main() -> int {
auto const x = 5;
if (x % 2 == 0) {
std::cout << "Even\n";
} else {
std::cout << "Odd\n";
}
return 0;
// --snip--
}
We can create a multiple branches based on various conditions using an else if
statement. These declared after the initial if statement.
#include <iostream>
// --snip--
auto main() -> int {
auto const x = 5;
if (x % 2 == 0) {
std::cout << "Even\n";
} else if (x % == 5) {
std::cout << "5 multiple\n";
} else {
std::cout << "Odd\n";
}
return 0;
// --snip--
}
switch statements
switch statements are a way to mix control flow with enums. switch statements are
given a enum object which are then matched against different cases ie. enum variants.
There is a default case that is used if no case is match, the equivalent of else
from if statements.
The cases of a switch statements automatically fallthrough to the next case if you do
not use a break statement to escape from the switch.
#include <iostream>
// --snip--
enum class colour : char {
red,
green,
blue
};
auto main() -> int {
auto const c = colour::red;
switch (c) {
case colour::red:
std::cout << "red\n";
break;
case colour::green:
std::cout << "green\n";
break;
case colour::blue:
std::cout << "blue\n";
break;
default:
std::cout << "unknown\n";
break;
}
return 0;
// --snip--
}
Because enums are fundamentally based on an underlying integral type, switch statements
thus can work on any integral type like char or int however, you have to be sure to
cover all the cases as there is no formally notion of pattern matching over integral
ranges.
Loops
while loop
while loops are the fundamental looping construct in C++. A while loops will repeat
as long as the condition remains true.
#include <iostream>
// --snip--
auto main() -> int {
auto i = 0uLL;
auto acc = 0uLL;
while (i < 10) {
acc += i;
i += 1;
}
std::cout << "Sum: " << acc << "\n";
return 0;
// --snip--
}
There is another while loop called a do-while loop. This has the same semantics as
a while loop but the loop condition is checked at the end of the loop instead of at the
start. This has the effect of running the loop at least once.
#include <iostream>
// --snip--
auto main() -> int {
auto i = 0uLL;
auto acc = 0uLL;
do {
acc += i;
i += 1;
} while (i < 1);
std::cout << "Sum: " << acc << "\n";
return 0;
// --snip--
}
for loop
for loops further abstract the concepts of loops by providing dedicated syntax for
initializing the loop counter and incrementing the loop unlike a while loop which only
only has syntax for checking the loop condition. We saw a for loop in our constexpr
example.
#include <iostream>
// --snip--
auto main() -> int {
auto acc = 0uLL;
for (auto i = 0; i < 10; i++) {
acc += i;
}
std::cout << "Sum: " << acc << "\n";
return 0;
// --snip--
}
range-for loop
In C++11, we got another for loop called a range-for loop. This loop is able to
automatically traverse C++ standard container types like array. This is beneficial
as it prevents us from incorrectly accessing/traversing the container ie. indexing out of
the array/containers bounds.
#include <iostream>
#include <array>
// --snip--
auto main() -> int {
auto const a = std::array {1, 2, 3, 4, 5};
auto acc = 0uLL;
for (auto const x : a) {
acc += x;
}
std::cout << "Sum: " << acc << "\n";
return 0;
// --snip--
}