http://www.cplusplus.com/reference/std/iterator/ a un tableau qui détaille les spécifications du § 24.2.2 du C++11. Fondamentalement, les itérateurs ont des étiquettes qui décrivent les opérations valides, et les balises ont une heiarchy. Ci-dessous est purement symbolique, ces classes n'existe pas réellement en tant que tel.
iterator {
iterator(const iterator&);
~iterator();
iterator& operator=(const iterator&);
iterator& operator++(); //prefix increment
reference operator*() const;
friend void swap(iterator& lhs, iterator& rhs); //C++11 I think
};
input_iterator : public virtual iterator {
iterator operator++(int); //postfix increment
value_type operator*() const;
pointer operator->() const;
friend bool operator==(const iterator&, const iterator&);
friend bool operator!=(const iterator&, const iterator&);
};
//once an input iterator has been dereferenced, it is
//undefined to dereference one before that.
output_iterator : public virtual iterator {
reference operator*() const;
iterator operator++(int); //postfix increment
};
//dereferences may only be on the left side of an assignment
//once an input iterator has been dereferenced, it is
//undefined to dereference one before that.
forward_iterator : input_iterator, output_iterator {
forward_iterator();
};
//multiple passes allowed
bidirectional_iterator : forward_iterator {
iterator& operator--(); //prefix increment
iterator operator--(int); //postfix decrement
};
random_access_iterator : bidirectional_iterator {
friend bool operator<(const iterator&, const iterator&);
friend bool operator>(const iterator&, const iterator&);
friend bool operator<=(const iterator&, const iterator&);
friend bool operator>=(const iterator&, const iterator&);
iterator& operator+=(size_type);
friend iterator operator+(const iterator&, size_type);
friend iterator operator+(size_type, const iterator&);
iterator& operator-=(size_type);
friend iterator operator-(const iterator&, size_type);
friend difference_type operator-(iterator, iterator);
reference operator[](size_type) const;
};
Vous pouvez soit se spécialiser std::iterator_traits<youriterator>
, ou de mettre la même typedefs dans l'itérateur lui-même, ou d'hériter d' std::iterator
(qui a ces typedefs). Je préfère la deuxième option, pour éviter de changer les choses dans l' std
d'espace de noms, et pour des raisons de lisibilité, mais la plupart des gens héritent de std::iterator
.
struct std::iterator_traits<youriterator> {
typedef ???? difference_type; //almost always ptrdif_t
typedef ???? value_type; //almost always T
typedef ???? reference; //almost always T& or const T&
typedef ???? pointer; //almost always T* or const T*
typedef ???? iterator_category; //usually std::forward_iterator_tag or similar
};
Remarque le iterator_category devrait être l'une des std::input_iterator_tag
, std::output_iterator_tag
, std::forward_iterator_tag
, std::bidirectional_iterator_tag
ou std::random_access_iterator_tag
, selon les catégories de votre itérateur a été en mesure de répondre à toutes les exigences pour comme détaillé ci-dessus. En fonction de votre itérateur, vous pouvez choisir de se spécialiser std::next
, std::prev
, std::advance
, et std::distance
, mais cela est assez rare. Dans de très rares cas, vous pouvez qui pour se spécialiser std::begin
et std::end
.
Votre conteneur doit probablement aussi un const_iterator
, ce qui est une (peut-être mutable) itérateur à données constantes qui est similaire à votre iterator
sauf qu'il doit être implicitement constructable à partir d'un iterator
, et les utilisateurs doivent être impossible de modifier les données. Il est commun pour les internes pointeur vers un pointeur non-constante des données, et ont iterator
hériter d' const_iterator
afin de minimiser la duplication de code.
Mon post à la Rédaction de votre propre Conteneur STL a une plus complète conteneur/itérateur prototype.