En utilisant boost :: iterator
-
26-09-2019 - |
Question
J'ai écrit une classe rare de vecteur (voir # 1 , # 2 .)
Je voudrais fournir deux types d'itérateurs:
Le premier ensemble, les itérateurs réguliers, peut pointer un élément quelconque, que ce soit ensemble ou à l'arrêt. S'ils sont lus, ils retournent soit la valeur de consigne ou value_type()
, si elles sont écrites, ils créent l'élément et renvoyer la référence lvalue. Ainsi, ils sont:
Random Access Traversal Iterator et Lisible et inscriptibles Iterator
Le deuxième ensemble, les itérateurs rares, iterate que sur les éléments de réglage. Comme ils ne ont pas besoin de créer paresseusement des éléments qui sont écrits, ils sont:
Random Access Traversal Iterator et Lisible et inscriptibles et Lvalue Iterator
J'ai besoin aussi des versions const des deux, qui ne sont pas inscriptibles.
Je peux remplir les blancs, mais ne savez pas comment utiliser boost :: iterator_adaptor pour commencer.
Voici ce que j'ai à ce jour:
template<typename T>
class sparse_vector {
public:
typedef size_t size_type;
typedef T value_type;
private:
typedef T& true_reference;
typedef const T* const_pointer;
typedef sparse_vector<T> self_type;
struct ElementType {
ElementType(size_type i, T const& t): index(i), value(t) {}
ElementType(size_type i, T&& t): index(i), value(t) {}
ElementType(size_type i): index(i) {}
ElementType(ElementType const&) = default;
size_type index;
value_type value;
};
typedef vector<ElementType> array_type;
public:
typedef T* pointer;
typedef T& reference;
typedef const T& const_reference;
private:
size_type size_;
mutable typename array_type::size_type sorted_filled_;
mutable array_type data_;
// lots of code for various algorithms...
public:
class sparse_iterator
: public boost::iterator_adaptor<
sparse_iterator // Derived
, typename array_type::iterator // Base (the internal array)
, value_type // Value
, boost::random_access_traversal_tag // CategoryOrTraversal
> {...}
class iterator_proxy {
???
};
class iterator
: public boost::iterator_facade<
iterator // Derived
, ????? // Base
, ????? // Value
, boost::?????? // CategoryOrTraversal
> {
};
};
aussi, est-ce illégal?
typedef boost::reverse_iterator<sparse_iterator> reverse_sparse_iterator;
La solution
Je ne suis pas sûr que vous voulez vraiment utiliser iterator_adaptor
dans votre cas -. Vous pouvez utiliser à la place iterator_facade
Une explication plus approfondie: iterator_adaptors
sont utilisés lorsque vous avez un itérateur existant (disons std::list<int>::iterator
) et que vous souhaitez réutiliser son comportement pour votre iterator, par exemple. votre iterator retourne la valeur de ce qui est dans la liste, mais la réutilisation code traversal deux fois de la iterator originale. Ou l'inverse: vous voudrez peut-être un itérateur qui va sauter certains des éléments dans la liste initiale, mais le retour des valeurs inchangées. Je ne sais pas si vous voulez baser votre iterator (comme dans le code de réutilisation) sur itérateurs de vos structures sous-jacentes, mais parler pour moi, je ne serais pas en particulier dans le cas de iterator comme vous le feriez non faible souhaiterez probablement créer quelques-uns proxy pour la référence qui signifie que vous ne pouvez pas utiliser un sous-jacent iterator code dereference()
et traversal est probablement facile. Vous pouvez, cependant, la base de votre sparse_iterator
sur certains itérateur qui fait itère sur les éléments existants du tableau si vous voulez.
Il y a des problèmes avec l'approche proxy, donc ne vous attendez pas à travailler parfaitement sans passer par de nombreux cerceaux. D'une part, la version const du iterator doit retourner effectif non encore value_type()
, qui expressions comme moyens iter->foo()
devrait se traduire par value_type().foo()
si l'entrée correspondante n'existe pas. Mais cela pose une difficulté, que pointer_proxy::operator->()
doit retourner quelque chose avec operator->
, de préférence un pointeur (certainement pas value_type()
). Ce qui nous amène à la question cruciale: Un pointeur sur quoi? Il y a des possibilités pour résoudre ce (pour un, si vous avez vos objets gérés par boost::shared_pointer
, vous pouvez simplement revenir un shared_pointer
à une instance new
'd).
Pour l'itérateur non faible, vous devez implémenter:
-
class reference_proxy
avec -
reference_proxy::operator&
(qui renverra probablement un proxy pointeur) -
reference_proxy::operator value_type&()
pour des utilisations const -
reference_proxy::operator const value_type&()
pour des utilisations non-const -
reference_proxy::foo()
pour toute fonction de membre defoo()
de value_type (autrement expressions comme(*it).foo()
AFAIK ne fonctionnera pas) -
class pointer_proxy
avec -
pointer_proxy::operator*
(retourner un reference_proxy) -
pointer_proxy::operator->
(faire quelque chose de sensé, voir ci-dessus)
Les paramètres au modèle de façade iterator devrait être:
-
Reference
: lereference_proxy
-
Pointer
: lepointer_proxy
La version clairsemée est plus simple: Si le sous-jacent iterator est sensible (.-À-dire correspond au comportement que vous voulez) et correctement mis en œuvre, vous pouvez simplement omettre les paramètres à la iterator_adaptor
(sauf pour les deux premiers), et de prendre toute la mise en œuvre .
Le problème "ne compile pas". Insérer typename