Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Подготовка к std::iterator устарела

Автор вопроса: Jonathan MeeОтветов: 2

21 мартаst комитет по стандартам проголосовал за прекращение поддержки std::iterator. предложено в P0174 а>:

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

До c++17 рекомендуется наследование от std::iterator, чтобы убрать скуку из шаблонной реализации итератора. Но устаревание потребует одну из этих вещей:

  1. Шаблон итератора теперь должен включать все необходимые typedef
  2. Алгоритмы, работающие с итераторами, теперь должны будут использовать auto, а не зависеть от итератора для объявления типов.
  3. Локи Астари предположил, что std::iterator_traits может быть обновлен для работы без наследования от std::iterator

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

  • @FirstStep Я надеюсь получить ответ, который не будет основан на мнении. Если комитет по стандартам осуждает класс, от которого я завишу в следующем году, я надеюсь, что у них будет направление, в котором они направляют меня прямо сейчас. Jonathan Mee 04.05.2016
  • То, что они устарели, не означает, что вы не можете продолжать использовать его какое-то время. Jesper Juhl 04.05.2016
  • Примечание. deprecating означает, что он больше не рекомендуется, но по-прежнему будет поддерживаться по крайней мере для другой версии стандарта. Martin York 04.05.2016
  • Итераторы в стандартной библиотеке выбрали вариант 1. Bo Persson 04.05.2016
  • @BoPersson Казалось бы, тогда мы должны сделать это? Jonathan Mee 04.05.2016
  • @LokiAstari - это еще слабее. Формально устаревание - это уведомление о том, что что-то может исчезнуть в будущем. Это все. Обратите внимание, что стандартные заголовки C устарели в C++ с 1998 года. Pete Becker 04.05.2016

c++deprecatediteratorc++17standardsc++14

Ответы

Ответ 1 · рейтинг 66 · Amir Kirsh

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

Учитывая, что не будет заменителя языка и не полагаясь на повышение или на вашу собственную версию базового класса итератора, следующий код, использующий 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;}
};

Ответ 2 · рейтинг 33 · Barry

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

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

Остается вариант 1. Думаю, нам нужно просто привыкнуть к написанию всего шаблонного. Я, например, приветствую наших новых повелителей запястного канала.

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы