Consider that we write the following code:
for (auto x : range) { code_block; }
The compiler will evaluate it to the following:
{
auto __begin = std::begin(range);
auto __end = std::end(range);
for ( ; __begin != __end; ++__begin) {
auto x = *__begin;
code_block
}
}
While looking at this code, it becomes obvious that the only requirements for the iterators are the following three operators:
- operator!=: unequal comparison
- operator++: prefix increment
- operator*: dereference
The requirements of the range are that it has a begin and an end method, which return two iterators that denote the beginning and the end of a range.
What we did in this recipe is just fit a simple number counting algorithm into the forward iterator interface. Implementing an iterator and a range always involves this minimum amount of boilerplate code, which can be a little bit annoying on the one hand. A look at the loop that uses num_range is, on the other hand, very rewarding because it looks so perfectly simple!