eigenen Iterator implementieren
-
Hallo,
ich habe aus einer Abfrage von einer C-Library eine Elementliste verpackt in einem mit anderen Dingen enthaltenen Struct bekommen. Für diese C-Lib und Struktur habe ich bisher eine Facade gebaut, die das mit weiteren zusammenhängenden Infos kapselt.
Jetzt würde ich auf dieser Facade gern einen eigenen Iterator implementieren. Ich habe schon Boost.Iterators gefunden, habe aber bisher die Dokumentation nicht wirklich verstanden.
Also ich würde gern auf der Facaden Klasse ein begin(), end() ++operator, *operator aufrufen aber bin unsicher was da alles zugehört. Kennt jemand ein einfaches Beispiel wir man zu einer derartigen Klasse eine Iteratorfunktion hinzufügt?
Danke!
-
class mein_iterator : public boost::iterator_facade<mein_iterator, ???> { public: ??? dereference() const { return ???; } bool equal(mein_iterator const& j) const { return ???; } void increment() { ??? } void decrement() { ??? } void advance(???) { ??? } ??? distance_to(mein_iterator const& j) const { return ???; } private: ??? };
-
Es schadet eventuell nicht, wenigstens einmal einen Iterator vollständig selber zu implementieren. Dann sieht man, dass es dabei zu Codewiederholung im großen Stil kommt und versteht, was für Arbeit einem durch Boost wie und warum abgenommen werden. Dann wird auch klar, warum die iterator_facade gerade die Funktionen haben möchte, die es möchte und wie diese aussehen müssen.
-
Hallo GmbH,
Da Du nichts über die Elementliste oder die Facade gesagt hast, lässt sich die Frage so pauschal nicht beantworten. Mal angenommen, Du hast eine Struktur wie diese hier:
struct S { double weissnich; int data[200]; int anzahl; // Anzahl der belegten Elemente in 'data[]' };
Dann ist es am einfachsten, mit einem boost.iterator_adaptor anzufangen.
#include <boost/iterator/iterator_adaptor.hpp> #include <cassert> // +-------------- Basistyp "ein Iterator" // | +-- Value Type des Iterators // | | class S_iterator : public boost::iterator_adaptor< S_iterator, int*, /*const*/ int, boost::forward_traversal_tag > { public: explicit S_iterator( int* p ) : iterator_adaptor_( p ) {} }; S_iterator begin( S& s ) { return S_iterator( s.data ); } S_iterator end( S& s ) { assert( s.anzahl >= 0 ); assert( s.anzahl <= sizeof(s.data)/sizeof(*s.data) ); return S_iterator( s.data + s.anzahl ); }
inklusive der beiden Funktionen
begin
undend
, die Dir Iteratoren auf den Anfang und das Ende des Containers liefern.So sind Aufrufe wie
S s; // s belegen ... copy( begin(s), end(s), ostream_iterator< int >( cout, " " ) ); // Elemente ausgeben cout << endl; S_iterator i = find( begin(s), end(s), 101 ); // suche 101 im Container
.. sofort möglich.
Wenn Du für den Valuetype
const int
stattint
wählst, so erhältst Du einenconst_iterator
- d.h. Du kannst über diesen Iterator die Elemente nicht verändern.
Den Traversal-Tag kann man hier auch gegenboost::bidirectional_traversal_tag
bzw.boost::random_access_traversal_tag
austauschen. Du solltest aber nur das auswählen, was Du wirklich brauchst, um ggf. versehentlichen Missbrauch zu unterbinden.Solltest Du kein Array sondern eine verkettete Struktur als Ausgangssituation haben, so ist hier beschrieben, wie dann vorzugehen ist. Aber auch das geschieht mit dem
iterator_adaptor
.iterator_facade
benötigt man eigentlich nie, solange darunter nur irgendwas containerartiges vorliegt.
Unter dem angegebenen Link ist auch beschrieben, wie man mit einem Klassentemplate einen iterator und den dazugehörigen const_iterator erzeugt. Inklusive der Konvertierung von iterator nach const_iterator.Gruß
Werner