Range-based `for` loops

albertopdrf

Alberto Pérez de Rada Fiol

Posted on March 22, 2021

Range-based `for` loops

Today we are going to learn about another very useful feature of Modern C++: Range-based for loops. As their name indicates, these kind of loops are useful when we want to iterate over the elements of a container, from beginning to end.

Here are some of the advantages of using range-based for loops:

  • Improve the readability of the code
  • Will be as optimized as possible
  • The awesome auto keyword can be used in the range declaration
  • There's no need to know the size of the container we want to iterate over

And, of course, all statements that work within a regular for loop (continue, break, etc.) also work within range-based for loops.

But enough talking, let's see some examples! Imagine we have a vector of ints, and we want to print all of its elements to stdout, how can we do it?

// Older standards
  // Option 1
for (int i = 0; i < (int)vector.size(); i++) {
  std::cout << vector[i] << std::endl;
}
  // Option 2
for (std::vector<int>::iterator it = vector.begin(); it != vector.end(); it++) {
  std::cout << *it << std::endl;
}

// Modern C++
for (auto element : vector) {
  std::cout << element << std::endl;
}
Enter fullscreen mode Exit fullscreen mode

That's very clean and concise! 🧐 And it gets even better when we use features from standards older than C++11. For instance, let's now imagine we have a map, with ints for both its keys and values. How can we loop through it, displaying its contents?:

// Older standards
for (int i = 0; i < (int)map.size(); i++) {
  std::pair<int, int> pair = map[i];
  std::cout << pair.first << ": " << pair.second << std::endl;
}

// Modern C++
for (auto [key, value] : map) {
  std::cout << key << ": " << value << std::endl;
}
Enter fullscreen mode Exit fullscreen mode

What was that? 😮 From C++17, we can use Structured Bindings to unpack the contents of a pair (or a tuple, in general) in such a compact way! But what if, for instance, we only cared about the values of the map? From C++20 we can use the Ranges Library to do:

for (auto value : map | std::views::values) {
  std::cout << value << std::endl;
}
Enter fullscreen mode Exit fullscreen mode

Simple and clean -- and there's more! Also from C++20, we can use the Init Statement if we need to. Let's add a very simple init statment to the last example so we can track the index of the current value, as I know you are already wondering what to do when the index is needed:

for (auto i = 0; auto value : map | std::views::values) {
  std::cout << "Value " << i++ << ": " << value << std::endl;
}
Enter fullscreen mode Exit fullscreen mode

Do you need more examples, or are you already convinced that range-based for loops are such a great addition to C++? Tell me in the comments! 👇

💖 💪 🙅 🚩
albertopdrf
Alberto Pérez de Rada Fiol

Posted on March 22, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Range-based `for` loops
cpp Range-based `for` loops

March 22, 2021

The awesome `auto` keyword
cpp The awesome `auto` keyword

January 25, 2021