0

I wanted to be able to iterate collections (I will only we doing this on vectors, if that's important) in reverse order with simple for (const auto& item : collection) style, and I found this answer which worked perfectly: https://stackoverflow.com/a/28139075/2195721. But then I wanted to be able to iterate either forward or backward, so I modified the code as shown here:

#include <iterator>
#include <iostream>
#include <vector>

template <typename T>
struct reversable_wrapper {
    T& iterable;
    bool reverse;

    reversable_wrapper(T&& iterable) : reversable_wrapper(iterable, true) {};
    reversable_wrapper(T&& iterable, bool reverse) : iterable(iterable), reverse(reverse) {};
};

template <typename T>
auto std::begin (reversable_wrapper<T> w)
{
    if (w.reverse) return std::rbegin(w.iterable);
    else return std::begin(w.iterable);
}

template <typename T>
auto std::end (reversable_wrapper<T> w)
{
    if (w.reverse) return std::rend(w.iterable);
    else return std::end(w.iterable);
}

template <typename T>
reversable_wrapper<T> reverse (T&& iterable) { return reversable_wrapper<T>(iterable); }

template <typename T>
reversable_wrapper<T> forward (T&& iterable) { return reversable_wrapper<T>(iterable, false); }

int main()
{
    std::vector<int> vec = {1,2,3};
    for (const auto& i : reverse(vec)) std::cout<<i<<std::endl;
    return 0;
}

Basically, what I wanted to achieve was for (const auto& item : cond ? forward(coll) : reverse(coll)). However, this code gives me following errors:

> $ g++ -std=c++14 iterators.cpp -o iterators
iterators.cpp: In instantiation of ‘auto std::begin(reversable_wrapper<T>) [with T = std::vector<int>&]’:
iterators.cpp:37:37:   required from here
iterators.cpp:18:38: error: inconsistent deduction for ‘auto’: ‘std::reverse_iterator<__gnu_cxx::__normal_iterator<int*, std::vector<int> > >’ and then ‘__gnu_cxx::__normal_iterator<int*, std::vector<int> >’
     else return std::begin(w.iterable);
                                      ^
iterators.cpp: In instantiation of ‘auto std::end(reversable_wrapper<T>) [with T = std::vector<int>&]’:
iterators.cpp:37:37:   required from here
iterators.cpp:25:36: error: inconsistent deduction for ‘auto’: ‘std::reverse_iterator<__gnu_cxx::__normal_iterator<int*, std::vector<int> > >’ and then ‘__gnu_cxx::__normal_iterator<int*, std::vector<int> >’
     else return std::end(w.iterable);

I can't figure which signature can I give to std::begin and std::end to overcome this and if this is possible at all.

I'm using g++ 5.4.0.

Community
  • 1
  • 1
Cthulhu
  • 1,379
  • 1
  • 13
  • 25

1 Answers1

0

Your problem is that you are trying to return one of std::vector::iterator or std::vector::reverse_iterator from your functions. Sadly, these are unrelated types.

I think your only chance is to write a reversible_iterator_wrapper which holds both types, and forwards its arguments to the right one. This is going to be tedious. The simplest (but not most efficient) option probably involves virtual functions!