Preparación para std :: iterator Ser desaprobado

El 21 de marzo, el comité de estándares votó para aprobar la desaprobación de std::iterator iterator propuesta en P0174 :

La secuencia larga de argumentos vacíos es mucho menos clara para el lector que simplemente proporcionar los typedef esperados en la definición de la clase en sí misma, que es el enfoque adoptado por el borrador actual, siguiendo el patrón establecido en C ++ 14

Se alentó la herencia Pre-C ++ 17 de std::iterator para eliminar el tedio de la implementación repetitiva del iterador. Pero la desaprobación requerirá una de estas cosas:

  1. Un texto repetitivo del iterador ahora deberá incluir todos los typedef necesarios
  2. Los algoritmos que trabajan con iteradores ahora necesitarán usar auto lugar de depender del iterador para declarar los tipos
  3. Loki Astari sugirió que std::iterator_traits se puede actualizar para que funcione sin heredar de std::iterator

¿Puede alguien aclararme cuál de estas opciones debería esperar, ya que diseño iteradores personalizados con miras a la compatibilidad con C ++ 17?

La opción 3 es una versión estrictamente más tipada de la Opción 1, ya que tiene que escribir todos los mismos typedefs pero también envuelve iterator_traits .

La opción 2 es inviable como solución. Puede deducir algunos tipos (por ejemplo, la reference es simplemente decltype(*it) ), pero no puede deducir iterator_category . No se puede diferenciar entre input_iterator_tag y forward_iterator_tag simplemente por la presencia de operaciones ya que no se puede verificar de forma refleja si el iterador cumple con la garantía de multipaso. Además, no se puede distinguir realmente entre esos y output_iterator_tag si el iterador produce una referencia mutable. Tendrán que ser provistos explícitamente en alguna parte.

Eso deja la Opción 1. Supongo que deberíamos acostumbrarnos a escribir todo el texto repetitivo. Yo, por mi parte, doy la bienvenida a nuestros nuevos señores del túnel carpiano.

Las alternativas discutidas son claras, pero creo que se necesita un ejemplo de código.

Dado que no habrá un sustituto del idioma y sin depender de la mejora o en su propia versión de la clase base del iterador, el siguiente código que usa std::iterator se fijará en el código que se encuentra debajo.

Con std::iterator

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

(Código de http://en.cppreference.com/w/cpp/iterator/iterator con el permiso del autor original).

Sin std::iterator

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