Как избежать специализации iterator_traits для каждого возможного создания шаблонного итератора? - PullRequest
0 голосов
/ 23 мая 2018

Я хочу увеличить свой диапазон на основе циклов, например, включив обратную итерацию.Мне удалось заставить его работать до некоторой степени, написав адаптер, но я заблудился о том, как сделать компоновщик adpaptor.

#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;
}

Первый цикл работает как брелок, но для второго я получаю сообщение об ошибке:

error: no type named ‘reference’ in ‘struct std::iterator_traits<reversed_range<int*> >’
             typename std::iterator_traits<IT>::reference operator*(){
                                                          ^~~~~~~~

Я знаю, почему это происходит, и я знаю, как я мог это исправить для этогочастный случай.Однако, если я правильно понимаю этот ответ , мне придется специализироваться iterator_traits для каждого возможного создания экземпляра моего reversed_iterator, что на самом деле неосуществимо.Я немного растерялся, большую часть времени я пишу свои собственные итераторы, я обнаруживаю, что пишу много шаблонов, просто чтобы достичь точки, когда я понимаю, что мне понадобится экспоненциально больше шаблонов, чтобы это заработало.Я имею в виду, что я даже не начал рассматривать const_iterator s.

Есть ли способ заставить работать выше (без необходимости специализировать iterator_traits для каждого iterator, который я когда-либо хочу повернуть вспять?

PS: помечен как C ++ 11, потому что это моя текущая область применения, но если есть улучшения в этом отношении, я не против использовать более новый стандарт.

1 Ответ

0 голосов
/ 23 мая 2018

std::iterator_traits<Iterator>::something - это просто Iterator::something по умолчанию.Таким образом, просто добавьте typedefs в ваш reversed_iterator тип:

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 */;

    // ...
};
...