Eigene Iteratoren schreiben



  • Hallo,

    ich möchte meine eigenen Iteratoren schreiben, die einen anderen Iterator
    kapselt. Der Iterator soll ein Filter sein, der nur bestimmte Elemente des
    gekapselten Iterator zurückgibt. Gibt es ne Basisklasse für die
    Standard-Iteratoren (von vector etc.)? Oder muss ich da für jeden Typ, den
    ich werwende einen Iterator schreiben, der so einen Iterator kapselt um
    so eine gemeinsame Basis zu schaffen.
    Da ich noch relativ neu bin...
    Wenn ich #include<vector> schreibe, dann inkludiert er doch in den Include-
    Verzeichnissen nach vector.hpp, oder? Aber ich find da nix, obwohl es funkt...
    Nur in meinem boost-Verzeichnis. Sonst hätte ich ja selbst nachgekuckt.

    Gruß,
    Iterator


  • Mod

    IteratorBasis schrieb:

    Hallo,

    ich möchte meine eigenen Iteratoren schreiben, die einen anderen Iterator
    kapselt. Der Iterator soll ein Filter sein, der nur bestimmte Elemente des
    gekapselten Iterator zurückgibt. Gibt es ne Basisklasse für die
    Standard-Iteratoren (von vector etc.)? Oder muss ich da für jeden Typ, den
    ich werwende einen Iterator schreiben, der so einen Iterator kapselt um
    so eine gemeinsame Basis zu schaffen.

    Verschiedene Iteratoren haben für gewöhnlich keine gemeinsame Bais - die Standardbibliothek macht ohnehin nur sehr sparsam von Vererbung Gebrauch. Eine Eigene Iteratorklasse, die einen anderen Iterator kapselt, ist nicht besonders schwer. Als Ausganngspunkt kannst du ja das hier nehmen

    template<typename T>
    class MyIterator;
    
    template<typename T> MyIterator< T >& operator++(MyIterator< T >&);
    template<typename T> MyIterator< T >& operator--(MyIterator< T >&);
    template<typename T> MyIterator< T >  operator++(MyIterator< T >&, int);
    template<typename T> MyIterator< T >  operator--(MyIterator< T >&, int);
    
    template<typename T> MyIterator< T >& operator+=(MyIterator< T >&, typename MyIterator< T >::difference_type);
    template<typename T> MyIterator< T >& operator-=(MyIterator< T >&, typename MyIterator< T >::difference_type);
    template<typename T> MyIterator< T >  operator+(const MyIterator< T >&, typename MyIterator< T >::difference_type);
    template<typename T> MyIterator< T >  operator-(const MyIterator< T >&, typename MyIterator< T >::difference_type);
    
    template<typename T> bool operator==(const MyIterator< T >&, const MyIterator< T >&);
    template<typename T> bool operator!=(const MyIterator< T >&, const MyIterator< T >&);
    template<typename T> bool operator< (const MyIterator< T >&, const MyIterator< T >&);
    template<typename T> bool operator<=(const MyIterator< T >&, const MyIterator< T >&);
    template<typename T> bool operator> (const MyIterator< T >&, const MyIterator< T >&);
    template<typename T> bool operator>=(const MyIterator< T >&, const MyIterator< T >&);
    
    template<typename T>
    class MyIterator
    {
    public:
        typedef typename std::iterator_traits< T >::difference_type   difference_type;
        typedef typename std::iterator_traits< T >::value_type        value_type;
        typedef typename std::iterator_traits< T >::pointer           pointer;
        typedef typename std::iterator_traits< T >::reference         reference;
        typedef typename std::iterator_traits< T >::iterator_category iterator_category;
    
    private:
        T current_;
    public:
        MyIterator() : current_() {}
        explicit MyIterator(T x) : current_( x ) {}
    
        reference operator*() const { return *current_; }
        const T& operator->() const { return current_; }
    
        reference operator[](difference_type n) const { return current_[ n ]; }
    
        friend MyIterator& operator++< T >(MyIterator&);
        friend MyIterator& operator--< T >(MyIterator&);
        friend MyIterator  operator++< T >(MyIterator&, int);
        friend MyIterator  operator--< T >(MyIterator&, int);
    
        friend MyIterator& operator+=< T >(MyIterator&, difference_type);
        friend MyIterator& operator-=< T >(MyIterator&, difference_type);
        friend MyIterator  operator+ < T >(const MyIterator&, difference_type);
        friend MyIterator  operator- < T >(const MyIterator&, difference_type);
    
        friend bool operator==< T >(const MyIterator&, const MyIterator&);
        friend bool operator!=< T >(const MyIterator&, const MyIterator&);
        friend bool operator< < T >(const MyIterator&, const MyIterator&);
        friend bool operator<=< T >(const MyIterator&, const MyIterator&);
        friend bool operator> < T >(const MyIterator&, const MyIterator&);
        friend bool operator>=< T >(const MyIterator&, const MyIterator&);
    };
    
    template<typename T> MyIterator< T >& operator++(MyIterator< T >& i)      { return ++i.current_, i; }
    template<typename T> MyIterator< T >& operator--(MyIterator< T >& i)      { return --i.current_, i; }
    template<typename T> MyIterator< T >  operator++(MyIterator< T >& i, int) { return MyIterator< T >( i.current_++ ); }
    template<typename T> MyIterator< T >  operator--(MyIterator< T >& i, int) { return MyIterator< T >( i.current_-- ); }
    
    template<typename T> MyIterator< T >& operator+=(MyIterator< T >& i, typename MyIterator< T >::difference_type n)
    {
        i.current_ += n;
        return i;
    }
    template<typename T> MyIterator< T >& operator-=(MyIterator< T >& i, typename MyIterator< T >::difference_type n)
    {
        i.current_ += n;
        return i;
    }
    template<typename T> MyIterator< T >  operator+(const MyIterator< T >& i, typename MyIterator< T >::difference_type n)
    {
        return MyIterator< T >( i.current_ + n );
    }
    template<typename T> MyIterator< T >  operator+(typename MyIterator< T >::difference_type n, const MyIterator< T >& i)
    {
        return i + n;
    }
    template<typename T> MyIterator< T >  operator-(const MyIterator< T >& i, typename MyIterator< T >::difference_type n)
    {
        return MyIterator< T >( i.current_ - n );
    }
    
    template<typename T> bool operator==(const MyIterator< T >& lhs, const MyIterator< T >& rhs) { return lhs.current_ == rhs.current_; }
    template<typename T> bool operator!=(const MyIterator< T >& lhs, const MyIterator< T >& rhs) { return lhs.current_ != rhs.current_; }
    template<typename T> bool operator< (const MyIterator< T >& lhs, const MyIterator< T >& rhs) { return lhs.current_ <  rhs.current_; }
    template<typename T> bool operator<=(const MyIterator< T >& lhs, const MyIterator< T >& rhs) { return lhs.current_ <= rhs.current_; }
    template<typename T> bool operator> (const MyIterator< T >& lhs, const MyIterator< T >& rhs) { return lhs.current_ >  rhs.current_; }
    template<typename T> bool operator>=(const MyIterator< T >& lhs, const MyIterator< T >& rhs) { return lhs.current_ >= rhs.current_; }
    

    Wenn ich #include<vector> schreibe, dann inkludiert er doch in den Include-
    Verzeichnissen nach vector.hpp, oder? Aber ich find da nix, obwohl es funkt...
    Nur in meinem boost-Verzeichnis. Sonst hätte ich ja selbst nachgekuckt.

    Gruß,
    Iterator

    Es ist dem Compiler überlassen, was bei #include <vector> passiert. Ein Header vector.hpp ist nicht Teil der Standardbibliothek - könnte aber als Erweiterung deines Compilers oder als Teil einer anderen Bibliothek existieren. iirc existiert für boosts mpl ein Header vector.hpp. Für boost is es allerdings empfohlene Praxis, Header mit explizitem relativen Pfad zu inkludieren (beginnend mit boost/ ).



  • camper: Wieso verwendest Du nicht 'std::iterator<>' als Basisklasse? Das erspart einem zumindest die ganzen Typedefs.

    /EDIT: Ah, Groschen gefallen. Vergisses.


  • Mod

    Im Grunde ist es witzig, dass in den wenigen Fällen, in denen die Standardbibliothek etwas mehr als das Notwendige "der Bequemlichkeit wegen" anbietet, dieses Mehr meistens überhaupt nichts bequmer macht. Jedenfalls spart man mit std::iterator nur eine handvoll Zeichen ein. Bei sowenig Ersparnis ist mir dann sogar die damit nötige Vererbung zuviel. 🙂

    Wenn es um weniger Schreiben geht, könnte man hier leicht sparen, indem man die Operatoren von vornherein nicht als Templates anlegt. Darauf habe ich hier der Systematik wegen verzichtet. Und falls sich jemand wegen den außerhalb der Klasse angelegten Operatoren wie ++ und += wundert: das dient der Imitation von Pointern, bei denen diese Operatoren auf rvalues nicht angewendet werden können (für Iteratoren im allgemeinen ist es undefiniertes Verhalten); man denke an das berüchtigte --container.end(). Für den Zuweisungsoperator geht das leider nicht und ich bin bekanntermaßen kein Fan von const T als Rückgabetyp.



  • Wenn du eh Boost hast (und auch sonst), solltest du Boost.Iterator verwenden. Da ist sogar bereits ein Iterator-Adapter namens filter_iterator drin, der so ungefähr das tun sollte, was du haben willst.



  • Vielen Dank für eure Antworten!

    Haben mir wirklich weitergeholfen



  • Wie erkenn ich denn, ob ich am Ende des Iterators angekommen bin,
    wenn ich meinen ursprünglichen vector (oder ähnliches) nicht mehr zur Verfügung
    hab, sondern nur den std::iterator?



  • IteratorBasis schrieb:

    Wie erkenn ich denn, ob ich am Ende des Iterators angekommen bin,
    wenn ich meinen ursprünglichen vector (oder ähnliches) nicht mehr zur Verfügung
    hab, sondern nur den std::iterator?

    indem Du Dir innerhalb des neuen (Filter-)Iterators auch den ursprünglichen Ende-Iterator merkst. Folge dem Link von .filmor

    .filmor schrieb:

    Da ist sogar bereits ein Iterator-Adapter namens filter_iterator drin, der so ungefähr das tun sollte, was du haben willst.

    und schau Dir das Beispiel an.

    Gruß
    Werner



  • Danke Werner,

    ich dachte es geht etvl. ohne (zusätzliches) cachen des letzten Elementes...



  • Warum geht das so nicht?

    #include <vector>
    
    template<typename T>
    class Test {
        Test();
        virtual ~Test();
    
    private:
        std::vector<T>::iterator it;
    };
    

    Der Kompiler meldet:
    9 Test.h expected `;' before "it"

    Mit nem normalen std::vector<T> geht es, warum nicht mit std::vector<T>::iterator?
    Vielen Dank im voraus,
    Iterator


  • Mod

    fehlt eine typename:

    private:
        typename std::vector<T>::iterator it;
    


  • Wie easy...

    Danke



  • Hallo,

    jetzt hab ich das Problem, dass ich nicht weiß wie ich über einen
    const std::vector<T> iteriere...
    Solange ich das const weglasse funktioniert es, sonst nicht...

    const std::vector<T>& listb = myMethod(); // liefert const std::vector<T>& zurück
        typename std::vector<T>::iterator it2 = listb.begin();
    

    Kann ich nicht über einen const Vector iterieren?

    Gruß,
    Iterator



  • Fehlermehldung:
    invalid conversion from `const MyObj* const* const' to `const MyObj**'



  • typename std::vector<T>::const_iterator it2
    

    vielleicht solltest du dir mal mehr über die std container und iteratoren durchlesen.

    http://www.sgi.com/tech/stl/Container.html
    http://www.sgi.com/tech/stl/Iterators.html


Anmelden zum Antworten