In C++11, we now have range-based for loops. Given a container c
, it is easy to write:
for ( auto x : c ) { do something with x }
but the STL deals in pairs of iterators.
Given two iterators, f
and l
, I still have to write:
for ( auto it=f; it != l; ++it ) { do something with *it }
- The first time I typed that, I got it wrong – I put a ‘,’ instead of the second ‘;’
- The second time I wrote that, I got it wrong again! – I used
it < l
instead ofit != l
.
Anyway, I would like to be able to write something like:
for ( auto x : f,l ) { do something with x }
But there is no support for that in C++11.
Enter iterator_pair
:
template <typename Iterator>
class iterator_pair {
public:
iterator_pair ( Iterator first, Iterator last ) : f_ (first), l_ (last) {}
Iterator begin () const { return f_; }
Iterator end () const { return l_; }
private:
Iterator f_;
Iterator l_;
};
With this I can now write:
for ( auto x : iterator_pair<type of f and l> ( f,l )) { do something with x }
which works, but is still annoying. Why should I have to put the type of the iterators there in my for loop? Worse than that, if this is in a template, I may not know what the type of f
and l
are!
But a helper function makes it all better:
template <typename Iterator>
iterator_pair<Iterator> make_iterator_pair ( Iterator f, Iterator l ) {
return iterator_pair<Iterator> ( f, l );
}
Now my code looks like I want:
for ( auto x : make_iterator_pair ( f,l )) { do something with x }
and I’m happy (for now).
I’m pretty sure that there’s a better name for this, but I’m going with iterator_pair
for the moment.
I specialized std::begin and std::end for pairs to create a range-based for loop. This also work if a function returns a pair of iterators, which happens quite often.
The name I’ve seen before is “range”, cf. Andrei Alexandrescu’s “On Iteration“.
You can read the mailing list archives for the ISO C++ Committee working group 9 (Ranges) here: http://www.open-std.org/pipermail/ranges/
Here’s another take on this: http://stackoverflow.com/questions/6167598/why-was-pair-range-access-removed-from-c11
It seems Boost::iterator_range provides exactly this.
http://www.boost.org/doc/libs/1_53_0/libs/range/doc/html/range/reference/utilities/iterator_range.html
Why not use std::for_each + lambda?
Because people really, really like range-based for loops.
(And because I like inventing things)
std::for_each feels a little messy for me. Comparing…
for_each( f, l, [](auto x){ … } );
with…
for( auto x : make_iterator_pair(f,l) ) …
What if you want to call this:
template
void DoStuff(Iterable iterable) {
for (auto elt : iterable) {
foo(elt);
}
}
? Then, you need something that has begin and end methods. iterator_pair FTW. I’m really surprised std lib does not have this already.
It is the point to get a range by iterators, so personally I’d call it make_iterator_range(f, l) or make_range_by_iterators(f, l). Anyway, a nice and simple solution.