Подтвердить что ты не робот

Подготовка к std:: iterator Будучи устаревшим

21 марта st комитет по стандартизации проголосовал за утверждение устаревшего std::iterator, предложенного в P0174:

Длинная последовательность аргументов void гораздо менее понятна читателю, чем просто предоставление ожидаемого typedef в самом определении класса, которое является подходом, используемым текущим рабочим черновиком, следуя шаблону, установленному на С++ 14

Наследование Pre-С++ 17 от std::iterator было рекомендовано удалить утомительную версию с использованием итератора. Но для устаревания потребуется одна из следующих вещей:

  • Оболочка итератора теперь должна включать все необходимые typedef s
  • Алгоритмы, работающие с итераторами, теперь должны использовать auto, а не в зависимости от итератора для объявления типов
  • Loki Astari предложил, что std::iterator_traits может быть обновлен, чтобы работать без наследующий от std::iterator

Может кто-нибудь просветить меня, по какому из этих вариантов я должен ожидать, поскольку я проектирую пользовательские итераторы с учетом совместимости с С++ 17?

4b9b3361

Ответ 1

Вариант 3 является строго более типичной версией Варианта 1, так как вам нужно написать все те же typedefs, но дополнительно wrap iterator_traits<X>.

Вариант 2 является нежизнеспособным как решение. Вы можете вывести некоторые типы (например, reference - это просто decltype(*it)), но вы не можете вывести iterator_category. Вы не можете различать input_iterator_tag и forward_iterator_tag просто наличием операций, так как вы не можете рефлексивно проверить, удовлетворяет ли итератор гарантией многопроходности. Кроме того, вы не можете отличить те и output_iterator_tag, если итератор дает изменяемую ссылку. Они должны быть явно предоставлены где-то.

Это оставляет Вариант 1. Предположим, мы должны просто привыкнуть писать весь шаблон. Я, например, приветствую наших новых бордель-туннельных повелителей.

Ответ 2

Обсуждаемые альтернативы ясны, но я считаю, что необходим пример кода.

Учитывая, что не будет языкового заменителя и не полагаться на boost или на собственную версию базового класса iterator, следующий код, который использует std::iterator, будет привязан к коду внизу.

С std::iterator

template<long FROM, long TO>
class Range {
public:
    // member typedefs provided through inheriting from std::iterator
    class iterator: public std::iterator<
                        std::forward_iterator_tag, // iterator_category
                        long,                      // value_type
                        long,                      // difference_type
                        const long*,               // pointer
                        const long&                // reference
                                      >{
        long num = FROM;
    public:
        iterator(long _num = 0) : num(_num) {}
        iterator& operator++() {num = TO >= FROM ? num + 1: num - 1; return *this;}
        iterator operator++(int) {iterator retval = *this; ++(*this); return retval;}
        bool operator==(iterator other) const {return num == other.num;}
        bool operator!=(iterator other) const {return !(*this == other);}
        long operator*() {return num;}
    };
    iterator begin() {return FROM;}
    iterator end() {return TO >= FROM? TO+1 : TO-1;}
};

(Код из http://en.cppreference.com/w/cpp/iterator/iterator с оригинальным разрешением автора).

Без std::iterator

template<long FROM, long TO>
class Range {
public:
    class iterator {
        long num = FROM;
    public:
        iterator(long _num = 0) : num(_num) {}
        iterator& operator++() {num = TO >= FROM ? num + 1: num - 1; return *this;}
        iterator operator++(int) {iterator retval = *this; ++(*this); return retval;}
        bool operator==(iterator other) const {return num == other.num;}
        bool operator!=(iterator other) const {return !(*this == other);}
        long operator*() {return num;}
        // iterator traits
        using difference_type = long;
        using value_type = long;
        using pointer = const long*;
        using reference = const long&;
        using iterator_category = std::forward_iterator_tag;
    };
    iterator begin() {return FROM;}
    iterator end() {return TO >= FROM? TO+1 : TO-1;}
};