The Iterator Iterator
So I was recently thinking about the code of an iterating for loop and why there is no functionality to retrieve an iterator with a range-based for loop. The range-based for loop was a hugely popular addition to C++, however it is limited to only returning dereferenced iterators. I don’t think I need to convince anyone of why one would need an iterator rather than a dereferenced iterator, there are plenty of use cases to warrant such a loop. The issue here is that to iterate over a range using a classic for loop takes quite a lot of characters, even with the wonderful auto it
that C++11 provides.
The Problem
Range-based for loops work like this:
But sometimes you need this:
Ideally, it would work like this:
I haven’t mastered meta-programming, so adding a for_it
definition is still on the horizon. So I propose this:
The Code
The full solution can be found here
The Iterator
The code here is small but powerful. itr
(the iterator iterator) is simply a container that holds a standard forward iterator. All operations work the same as most other forward iterators except that the iterator iterator dereference operator returns an iterator, not a dereferenced iterator.
This is a minimal implementation of only what is needed for range-based for loops. A proper implementation would implement std::iterator
and also follow the rules of `InputIterator’
In addition to the iterator class, a make
function has been implemented. The idea here is to save the user from having to define the type of itr
themselves, a similar idea to make_tuple
and make_shared
. My make
function has been simply defined as iit
to save some characters.
Ref and Val
iit
is defined around a universal reference (l-value or r-value) and a return type conditionally tied to if the type is l-value or r-value. This allows iit
to accept the value by reference using the class ref
, or move construct the type val
. Primarily, the ref
and val
encapsulating containers provide the begin
and end
functions which return itr
. Additionally, having a ref
and val
class allows iit
to encapsulate the passed in container and keep an r-value alive through the lifetime of ref
. Here are the definitions of ref
and val
:
Usage
Without the val
container to capture the r-value and store it, the vector would go out of scope.
Here, v is sent to ref
which only holds a reference to vector, no copies needed.
Thanks for reading!
Brian Rackle