2009-10-20 5 views
11

J'ai une classe dans laquelle je veux exposer une liste de structures (qui ne contiennent que des entiers). Je ne veux pas l'extérieur de modifier ces données, juste au-dessus et itérer les lire Exemple:Rendre ma classe C++ itérable via BOOST_FOREACH

struct TestData 
{ 
    int x; 
    int y; 
    // other data as well 
} 

class IterableTest 
{ 
    public: 
    // expose TestData here 
}; 

maintenant dans mon code que je veux utiliser ma classe comme ceci:

IterableTest test; 
BOOST_FOREACH(const TestData& data, test.data()) 
{ 
    // do something with data 
} 

J'ai déjà lu cet article http://accu.org/index.php/journals/1527 sur les espaces membres. Cependant, je ne veux pas (ou ne peux pas) enregistrer tous TestData dans un vecteur interne ou quelque chose. Cela est dû au fait que la classe elle-même ne possède pas le stockage, c'est-à-dire qu'il n'y a en réalité aucun conteneur sous-jacent auquel la classe peut accéder directement. Cependant, la classe elle-même peut interroger un composant externe pour obtenir l'élément suivant, précédent ou ith. Donc en gros je veux que ma classe se comporte comme si elle avait une collection, mais en fait elle n'en a pas. Des idées?

+4

ne suffit-il pas de fournir des fonctions de début/fin renvoyant des itérateurs appropriés? – jalf

+0

oui, mais je n'ai pas un conteneur sous-jacent qui pourrait me fournir ces itérateurs – newgre

+0

alors écrivez-les vous-même. :) La bibliothèque Boost.Iterator devrait vous permettre de démarrer assez rapidement. – jalf

Répondre

5

Il semble que vous devez écrire vos propres itérateurs.

La bibliothèque Boost.Iterator dispose d'un certain nombre de modèles utiles. J'ai utilisé leur classe de base Iterator Facade plusieurs fois, et il est facile et facile de définir vos propres itérateurs en l'utilisant.

Mais même sans cela, les itérateurs ne sont pas une science de fusée. Ils ont juste à exposer les bons opérateurs et typedefs. Dans votre cas, ils vont juste être des wrappers autour de la fonction de requête qu'ils doivent appeler quand ils sont incrémentés. Une fois que vous avez défini une classe d'itérateur, il vous suffit d'ajouter les fonctions membres begin() et end() à votre classe.

Il semble que l'idée de base sera d'appeler votre fonction de requête lorsque l'itérateur est incrémenté, pour obtenir la valeur suivante. Et dereference devrait alors retourner la valeur récupérée du dernier appel de requête. Il peut être utile de jeter un coup d'œil à la bibliothèque standard stream_iterator pour une partie de la sémantique, car ils doivent également contourner certains problèmes "nous n'avons pas vraiment de conteneur, et nous ne pouvons pas créer d'itérateurs pointant partout ailleurs que dans la position actuelle du flux ». Par exemple, en supposant que vous deviez appeler une fonction query() qui renvoie NULL lorsque vous avez atteint la fin de la séquence, la création d'un «itérateur de fin» sera difficile. Mais vraiment, tout ce dont vous avez besoin est de définir l'égalité de sorte que "les itérateurs soient égaux s'ils stockent NULL comme valeur cachée". Donc, initialisez l'itérateur "fin" avec NULL.

Il peut être utile de rechercher la sémantique requise pour les itérateurs d'entrée, ou si vous lisez spécifiquement la documentation de Boost.Iterator pour les itérateurs à un seul passage. Vous ne serez probablement pas capable de créer des itérateurs multipass. Alors cherchez exactement quel comportement est requis pour un itérateur à un seul passage, et respectez-le.

+0

Et parce que je suis un gars sympa: le concept Input Iterator >> http://www.sgi.com/tech/stl/InputIterator.html –

0

Si votre type de collection présente une interface de conteneur standard, vous n'avez rien à faire pour que votre BOOST_FOREACH fonctionne avec votre type. En d'autres termes, si votre type a const_iterator typedefs imbriqués, et begin() et end() fonctions membres, BOOST_FOREACH sait déjà comment itérer sur votre type. Aucune autre action est nécessaire.

http://boost-sandbox.sourceforge.net/libs/foreach/doc/html/boost_foreach/extending_boost_foreach.html

+0

Je sais à ce sujet, mais d'où pourrais-je obtenir ces itérateurs? Il n'y a pas de conteneur sous-jacent dont je pourrais utiliser les itérateurs – newgre

0

Sur la page Boost documentation for_each:

itère BOOST_FOREACH sur des séquences. Mais qu'est-ce qui se qualifie comme une séquence, exactement? Puisque BOOST_FOREACH est construit au-dessus de Boost.Range, il supporte automatiquement les types que Boost.Range reconnaît comme séquences. Plus précisément, BOOST_FOREACH fonctionne avec les types qui satisfont le concept de plage unique. Par exemple, nous pouvons utiliser BOOST_FOREACH avec:

Questions connexes