I want to pimp up my ranged based for loops, for example by enabling reversed iteraton. I managed to get it working to some degree by writing an adaptor, but I am lost on how to make the adpaptor composable.
#include <iostream>
template <typename IT> struct reversed_range {
struct reversed_iterator {
IT it;
reversed_iterator(IT it): it(it){}
reversed_iterator& operator++(){
--it;
return (*this);
}
typename std::iterator_traits<IT>::reference operator*(){
IT tmp = it;
--tmp;
return *tmp;
}
bool operator==(const reversed_iterator& other) const {
return it == other.it;
}
bool operator!=(const reversed_iterator& other) const {
return !(*this == other);
}
};
IT itbegin;
IT itend;
reversed_range(const IT& b,const IT& e): itbegin(b),itend(e){}
reversed_iterator begin() const { return reversed_iterator(itend); }
reversed_iterator end() const { return reversed_iterator(itbegin); }
};
template <typename IT>
reversed_range<IT> reverse_range(const IT& begin,const IT& end) {
return reversed_range<IT>(begin,end);
}
template <typename C>
reversed_range<C> reverse_range(const C& c) {
return reversed_range<typename C::iterator>(std::begin(c),std::end(c));
}
int main() {
int x[] = {1,2,3,4,5};
for (auto y : reverse_range(std::begin(x),std::end(x))){
std::cout << y << "\t";
}
for (auto y : reverse_range(reverse_range(std::begin(x),std::end(x)))){
std::cout << y << "\t";
}
return 0;
}
The first loop works like a charm, but for the second I get the error:
error: no type named ‘reference’ in ‘struct std::iterator_traits<reversed_range<int*> >’
typename std::iterator_traits<IT>::reference operator*(){
^~~~~~~~
I know why this happens and I know how I could fix it for this particular case. However, if i correclty understand this answer I would have to specialize iterator_traits
for each possible instantiation of my reversed_iterator
which isnt really feasible. I am a bit lost, most of the time I write my own iterators I find myself writing lots of boilerplate just to reach a point where I realize that I would need exponentially more boilerplate to get it working. I mean I didnt even start to consider const_iterator
s.
Is there a way to get the above working (whithout having to specialize iterator_traits
for each iterator
I ever want to reverse?
PS: tagged as C++11, because thats my current scope, but if there are improvements with respect to this, I wouldnt mind to use a newer standard.
std::iterator_traits<Iterator>::something
is simply Iterator::something
by default. Thus, simply add the typedefs into your reversed_iterator
type:
struct reversed_iterator {
using difference_type = typename std::iterator_traits<IT>::difference_type;
using value_type = typename std::iterator_traits<IT>::value_type;
using pointer = typename std::iterator_traits<IT>::pointer;
using reference = typename std::iterator_traits<IT>::reference;
using iterator_category = /* appropriate category */;
// ...
};