Подготовка к 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?
Ответы
Ответ 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;}
};