Consider a container like so:

std::vector#include <vector><int> cont = {0, 1, 2, 3};

Range-based for loops allow you to loop over each element in a container without writing an index or iterator:

for (auto element : cont) {
  std::cout#include <iostream> << element << "\n";
}

The above is equivalent to this for loop:

for (size_t i = 0; i < cont.size(); i++) {
  auto element = cont[i];
  std::cout#include <iostream> << element << "\n";
}

And you can also get elements by reference if you want mutation:

for (auto& element : cont) {
  element *= 2;
}

You can get elements as a const if you do not need mutation:

for (const auto& element : cont) {
  std::cout#include <iostream> << element << "\n";
}

An operation can be lazy-evaluated on a view (viewable range) in the for loop using the pipe operator (|):

#include <ranges>
for (auto i : std::views#include <ranges>::all(cont) | std::views#include <ranges>::take(2)) {
  std::cout#include <iostream> << i << "\n";
}

References