77 votes

Préparation pour le std::iterator Déconseillé

Le 21 Marsst le comité des normes a voté pour approuver le retrait de l' std::iterator proposé dans P0174:

La longue séquence de la vacuité des arguments est beaucoup moins clair pour le lecteur que de simplement fournir des attendus de l' typedefs dans la définition de la classe elle-même, qui est l'approche adoptée par l'actuel projet de travail, suivant le modèle défini en C++14

Pré-C++17 héritage std::iterator a été encouragé à éliminer l'ennui de itérateur passe-partout de mise en œuvre. Mais la dépréciation aura besoin de l'une de ces choses:

  1. Un itérateur standard devra inclure toutes les typedefs
  2. Les algorithmes de travail avec les itérateurs devrez maintenant utiliser auto plutôt que selon l'itérateur de déclarer les types de
  3. Loki Astari a suggéré qu' std::iterator_traits peut être mis à jour pour fonctionner sans hériter de std::iterator

Quelqu'un peut-il m'éclairer sur laquelle de ces options je devrais attendre, comme je l'ai design personnalisé itérateurs avec un oeil vers C++17 de compatibilité?

66voto

Amir Kirsh Points 1264

L'examen des solutions de rechange sont claires, mais je pense qu'un exemple de code est nécessaire.

Étant donné qu'il n'y aura pas une langue de substitution et sans s'appuyer sur un coup de pouce ou sur votre propre version de l'itérateur de la classe de base, le code suivant qui utilise std::iterator sera fixé par le code en dessous.

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

(Code de http://en.cppreference.com/w/cpp/iterator/iterator avec de l'auteur original de l'autorisation).

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

33voto

Barry Points 45207

L'Option 3 est strictement plus-typage version de l'Option 1, car vous avez à écrire tout de même typedefs mais en plus, enveloppez - iterator_traits<X>.

L'Option 2 est plus viable comme solution. Vous pouvez déduire certains types (par exemple, reference est juste decltype(*it)), mais vous ne pouvez pas déduire iterator_category. Vous ne pouvez pas différencier input_iterator_tag et forward_iterator_tag simplement en présence d'opérations, puisque vous ne pouvez pas le réflexe de vérifier si l'itérateur satisfait le multipass garantie. En outre, vous ne peut pas vraiment distinguer entre ceux-ci et l' output_iterator_tag si l'itérateur donne une mutable référence. Ils devront être expressément prévu quelque part.

Qui laisse l'Option 1. Imagine qu'on doit juste s'habituer à l'écriture de tous les passe-partout. Pour ma part, je souhaite la bienvenue à notre nouveau canal carpien suzerains.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X