Before C++11, when programmers wanted to display the elements stored in a vector, they had to write something like this:
template <typename T>
void show(const T& x)
{
for (typename T::const_iterator i = x.begin(); i != x.end(); ++i)
std::cout << *i << std::endl;
}
That method will be useful to show any collection that has a begin() and an end() and an iterator with an operator++(int), an operator!=() and an operator*() properly implemented.
C++11 and later versions ship with a very useful range-based for loop that makes iterations easier to write and read. This new for loop works also with plain-old arrays.
So, the code above can be rewritten like this in modern C++:
template <typename T>
void show(const T& x)
{
for (auto& i : x)
std::cout << i << std::endl;
}
As shown, the syntax is very similar to Java’s “enhanced-for” loop, and the resulting code is much easier to write and understand compared to the old version.
In the next example, you can see how this for loop can be used with several containers and arrays:
#include <vector>
#include <array>
#include <iostream>
template <typename T>
void show(const T& t)
{
for (auto& i : t)
std::cout << i << std::endl;
}
int main()
{
int ints[] = { 10, 20, 30, 40, 50 };
show(ints);
std::cout << "*****" << std::endl;
std::vector<std::string> s = {
"Monday", "Tuesday",
"Wednesday", "Thursday",
"Friday", "Saturday", "Sunday"
};
show(s);
std::cout << "*****" << std::endl;
std::array<string, 12> m = {
"January", "February",
"March", "April", "May",
"June", "July", "August",
"September", "October",
"November", "December"
};
show(m);
std::cout << "*****" << std::endl;
return 0;
}
Custom classes can also be iterated using the new for loop if the required methods are implemented, as in this example:
#include <vector>
#include <array>
#include <iostream>
template <typename T>
void show(const T& t)
{
for (auto& i : t)
std::cout << i << std::endl;
}
class RangeIterator
{
private:
int _index;
public:
explicit RangeIterator(int index) : _index(index) { }
bool operator!=(const RangeIterator& x) const
{
return _index != x._index;
}
const int& operator*() const
{
return _index;
}
int& operator++()
{
return ++_index;
}
};
template <int N, int M>
class Range
{
public:
using const_iterator = const RangeIterator;
const_iterator begin() const
{
return const_iterator{N};
}
const_iterator end() const
{
return const_iterator{M};
}
};
int main()
{
Range<10, 20> r;
show(r);
return 0;
}
Programmers can even iterate over a range of numbers (like the classic for loop) in this very elegant way:
int main()
{
for (auto i : Range<10, 20>{})
{
std::cout << i << std::endl;
}
}
The class to be iterated needs to have begin() and end() methods that return an iterator.
An iterator is basically a class that implements operator++(), operator!=(), and operator*() to access the next element, verify if there are more elements, and return the current element, respectively. Its semantics mimic pointer arithmetic to behave similarly to how a plain old array can be iterated.