Підготовка до std :: iterator Не підтримується


76

З 21 березня ст на стандартах комітет проголосував затвердити Deprecation з std::iteratorзапропонованих в P0174 :

Довга послідовність недійсних аргументів набагато менш зрозуміла для читача, ніж просто надання очікуваних typedefs у самому визначенні класу, що є підходом поточного робочого проекту, дотримуючись шаблону, встановленого в

Раніше спадщину від std::iteratorзаохочувалося видалити теді з ітератора зразка реалізації. Але для припинення існування потрібно одне з таких речей:

  1. Тепер шаблон ітератора повинен включати всі необхідні typedefs
  2. Тепер потрібно використовувати алгоритми, що працюють з ітераторами auto а не залежати від ітератора для оголошення типів
  3. Локі Астарі припустив, що std::iterator_traitsможе бути оновлений до роботи без успадкування відstd::iterator

Чи може хтось пояснити мені, на який із цих варіантів мені слід розраховувати, оскільки я розробляю власні ітератори, орієнтуючись на сумісність?


6
@FirstStep Я сподіваюся отримати відповідь, яка не буде заснована на думках. Якщо стандартний комітет відмовиться від класу, від якого я буду залежати наступного року, я сподіваюся, що у них буде напрямок, до якого вони спрямовують мене зараз.
Джонатан Мі

2
Те, що вони це знецінюють, не означає, що ви не можете продовжувати користуватися ним деякий час.
Jesper Juhl

4
Ітератори в стандартній бібліотеці вибрали варіант 1.
Бо Перссон,

1
@LokiAstari - це навіть слабше, ніж це. Формально застарівання - це повідомлення про те, що щось може піти в майбутньому. Це все. Зверніть увагу, що стандартні заголовки C застаріли в C ++ з 1998 року.
Піт Беккер,

1
@JonathanMee - ні, це не даремно. Це не було необхідністю, але це має переваги.
Піт Беккер,

Відповіді:


61

Обговорювані альтернативи зрозумілі, але я вважаю, що потрібен приклад коду.

З огляду на те, що не буде мови, що замінює мову, і не покладаючись на boost або на власну версію базового класу ітератора, наступний код, який 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
@AmirKirsh operator*повинен повернутися reference, вам потрібно operator->повернення, pointerхоча це не має сенсу дляlong
Райан Хейнінг

1
Я знайшов досить фантастичну статтю про це тут також, що викладені обґрунтування.
Jason C

33

Варіант 3 - це суворо більш набрана версія Варіанту 1, оскільки вам доведеться писати все те саме, typedefsале додатково обгортання iterator_traits<X>.

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

Це залишає Варіант 1. Здогадуємось, нам слід просто звикнути писати весь шаблон. По-перше, я вітаю наших нових володарів зап’ястного тунелю.


3
Якщо вам дійсно подобається те, що std::iteratorробить, ви можете просто написати свою власну версію. Отже, ризик зап’ястного тунелю дуже завищений.
TC

5
@JonathanMee Це не має жодного сенсу.
Barry

7
@JonathanMee Dude. "Ітератор" та "Вхідний ітератор" не є рівнозначними .
Barry

7
@TemplateRex Це був жарт. Незважаючи на це, здається безглуздим заперечення std::iteratorна користь ... кожен, хто зараз пише власну копію, std::iteratorщоб вирішити цю проблему в будь-якому випадку.
Barry

3
пов’язані: stackoverflow.com/q/29108958/819272 Це більш загальна тенденція у Стандарті видаляти безглузді базові класи, що містять лише typedefs (unary_function тощо)
TemplateRex
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.