10
votes

Pourquoi mon itérateur personnalisé ne fonctionne-t-il pas avec la copie stl?


4 commentaires

Et comment l'algorithme devrait-il savoir ce que type d'itérateur est? Par exemple, l'algorithme peut être plus rapide avec des itérateurs d'accès aléatoire, mais comment savoir si votre itérateur est un accès aléatoire ou non?


Parce que tous vos itérateurs devraient commencer comme ça struct file_inserter: boost :: iterator_facade <...> {...


@ALFC: FWIW, je viens d'essayer d'écrire un médicament simple avec boost :: iterator_facade et a immédiatement eu des ennuis. Stackoverflow.com/questions/43481025 Depuis que l'OP était aussi essayer de créer un médicamentiterator " itérator_facade résout tous vos problèmes de magie "n'est pas un conseil utile. Se passe, itérator_facade crée des problèmes à part entière. (Devrait toujours l'utiliser, mais ce n'est pas une réponse à une ligne. C'est une réponse multiligne avec plusieurs mises en garde et, espérons-le, un exemple.)


@Queuxplusone. Oui, le commentaire est un indice, pas une réponse.


4 Réponses :


18
votes

Votre Queue_inserter Code> doit être dérivé de std :: itérateur code> de sorte que tous les caractères de caractères tels que valeur_type code> sont correctement définis car ceux-ci sont utilisés. Aux algorithmes STL, cette définition fonctionne:

template< typename T, typename U >
class queue_inserter : public std::iterator<std::output_iterator_tag, T>{
    queue<T, U> &qu;  
public:
    queue_inserter(queue<T,U> &q) : qu(q) { }
    queue_inserter<T,U> operator ++ (int) { return *this; }
    queue_inserter<T,U> operator ++ () { return *this; }
    queue_inserter<T,U> operator * () { return *this; }
    void operator = (const T &val) { qu.push(val); }
};


7 commentaires

C'est incroyable à quel point la STL a été mal conçue. Je pensais que tout le point d'itérateurs était-ce que je pouvais rouler le mien? Est-ce que Char * hérit de std :: itérateur? Mais merci pour l'info. :-)


Vous pouvez toujours me contenter de ne pas dériver .. (Je ne l'ai pas essayé cependant), mais vous avez besoin de tous ces Typefs vous-même.


@Frank Krueger: Comment concevriez-vous les algorithmes de la bibliothèque standard pour travailler efficacement s'ils ne peuvent pas déterminer les propriétés des types dont ils ont besoin pour fonctionner? Ce n'est pas un problème trivial. STD :: Itérator_Traits est spécialisé par la mise en œuvre des types de pointeur afin que ceux-ci puissent être utilisés avec des algorithmes sans autre travail de la part de l'utilisateur.


En réalité, le type d'itérateur doit être std :: Sortie_Put_iterator_tag , Bidirectionnel implique que opérateur - () est défini.


@FRANK: C'est un commentaire médiocre. La manière dont les itérateurs sont conçus est une technique très courante utilisée en C ++ pour passer des informations de type sur le type lors de l'utilisation de modèles. Faites juste une recherche sur des traits de Quicj et je suis sûr que vous trouvez des articles appropriés dessus. Remarque: les algorithmes utilisent des traits. Pour les types de pointeur (comme Char *), ils sont explicitement définis pour les objets de classe qu'ils rapprochent au type pour les informations requises. Toutes les choses très basiques.


Mais sont Typefs héritées de cette façon? Je suis confus entre cette réponse et une autre réponse ( Lien ).


Fyi @hindol, héritant de std :: itérateur donnera à votre enfant la classe de ces membres Typefs. (link) dit que Même si l'enfant a ces Typefefs, l'enfant ne peut pas réellement les utiliser en interne elle-même (par exemple, pour déclarer opérateur de référence * () const ) ; C'est uniquement parce que l'enfant est un modèle . Les TypeDEFS sont dans un sens "uniquement visible pour les étrangers", à moins que l'enfant ne saute par des cerceaux pour y accéder lui-même.



8
votes

Dérivez-le de STD :: Itérateur. Si vous êtes intéressé, le Dr Dobb's a un article sur des conteneurs personnalisés et des itérateurs.


0 commentaires

6
votes

Votre itérateur ne répond pas à l'exigence d'un type "assignable" qui est une exigence d'un itérateur de sortie car il contient une référence et des types assignables doivent s'assurer qu'après t = u que < code> t est équivalent à u .

Vous pouvez fournir une spécialisation appropriée pour itérator_traits pour votre itérateur soit en dérivant d'une spécialisation de std :: itérateur ou en fournissant une explicitement. xxx


2 commentaires

Merci de me donner la curiosité d'en savoir plus sur itérator_traits ! Jamais le savait avant. Bien qu'une spécialisation explicite de itérator_traits n'est pas nécessaire. Voir ma réponse :)


itérator_traits , char_traits , pointeur_traits; , regex_traits et allocator_traits aussi! Il y a aussi un include, mais c'est complètement indépendant.



4
votes
#include <queue>
#include <algorithm>
#include <iterator>
#include <iostream>

using namespace std;

template< typename T, typename U >
class queue_inserter
{
    queue<T, U> &qu;

public:
    // for iterator_traits to refer
    typedef output_iterator_tag iterator_category;
    typedef T value_type;
    typedef ptrdiff_t difference_type;
    typedef T* pointer;
    typedef T& reference;

    queue_inserter(queue<T,U> &q) : qu(q) { }
    queue_inserter<T,U>& operator ++ () { return *this; }
    queue_inserter<T,U> operator * () { return *this; }
    void operator = (const T &val) { qu.push(val); }
};

template< typename T, typename U >
queue_inserter<T,U> make_queue_inserter(queue<T,U> &q)
{
    return queue_inserter<T,U>(q);
}

int main()
{
    // uses initalizer list (C++0x), pass -std=c++0x to g++
    vector<int> v({1, 2, 3});
    queue<int, deque<int>> q;
    copy(v.cbegin(), v.cend(), make_queue_inserter(q));
    while (!q.empty())
    {
        cout << q.front() << endl;
        q.pop();
    }
}
This should do it with iterator_traits; a helper struct in <iterator> which defines all types an iterator should typically define. Functions in <algorithm>, refer to these types when required like iterator_traits<it>::iterator_category or say iterator_traits<it>::value_type, etc. Just defining them inside one's custom iterator would do the trick. This is the modern way of writing iterators, as opposed to the classical way of inheriting from std::iterator. Having a look at <iterator> reveals that even std::iterator defines these types i.e. iterator_category, difference_type, etc. This is the reason, when inherited from std::iterator, the derived iterator class gets these due to heredity.

2 commentaires

Pourquoi hériter de std :: itérateur obsolète et où je peux en trouver plus sur la façon de faire la bonne façon alors?


S'il vous plaît voir Cette réponse pour plus de détails. Et désolé pour la réponse très tardive, je ne savais pas que vous auriez demandé.