Iterator begin und end falsch



  • Hallo zusammen,

    ich habe für eine eigene List einen Iterator mit Eurer Hilfe zusammengebastelt. Das heißt fast, ich mußt nun feststellen, dass ich einen Fall nicht getestet habe, die leere Liste.

    Die Liste als solches ist im wesentlichen:

    template <typename T>
            class List {
            public:
    
                List();
                List(const List & orig);
                virtual ~List();
    
                List & add(const T & t);
                List & add(const List<T> & tList);
                List & add(const T* tArray, size_t laenge);
                List & add(const std::vector<T> t);
    
                void clear();
    
                size_t size() const;
    
                bool contains(const T & a) const;
    
                void remove(const T & a);
                void remove(T & a);
                void remove(const List<T> & tList);
    
                List<T> & unify(List<T> & tList);
    
                T & get(size_t index);
                T const & get(size_t index) const;
    
                void sort();
    
                void pop();
                T & first();
                T first() const;
                T & last();
                T last() const;
    
                bool operator==(const List<T> & other) const;
    
                T & getMinElem();
    
            protected:
    
                typedef std::vector<T> TList;
                TList queue;
    
            public:
    
                template <typename L>
                class Iterator : public std::iterator<std::forward_iterator_tag, L> {
    
                    L * pos;
    
                    friend class List<T>;
    
                    explicit Iterator(L * aPos);
    
                public:
    
                    Iterator();
    
                    Iterator(Iterator<typename std::remove_const<L>::type > const & other);
    
                    L & operator*();
    
                    Iterator<L> & operator++(); // prefix
                    Iterator<L> operator++(int); //postfix
    
                    bool operator !=(const Iterator<L> & other) const;
                    bool operator ==(const Iterator<L> & other) const;
    
                    Iterator<L> operator=(const Iterator<L> & other);
                    Iterator<L> operator+(const unsigned int position);
                    Iterator<L> operator-(const unsigned int position);
    
                };
    
                typedef Iterator<T> iterator;
                typedef Iterator<const T> const_iterator;
    
                iterator begin();
                const_iterator begin() const;
    
                iterator end();
                const_iterator end() const;
    
            };
    

    Und der Iterator als solches ist:

    template <typename T>
            template <typename L>
            List<T>::Iterator<L>::Iterator() : pos(NULL) {
            }
    
            template <typename T>
            template <typename L>
            List<T>::Iterator<L>::Iterator(L * aPos) : pos(aPos) {
            }
    
            template <typename T>
            template <typename L>
            List<T>::Iterator<L>::Iterator(Iterator< typename std::remove_const<L>::type > const & other) : pos(other.pos) {
            }
    
            template <typename T>
            template <typename L>
            L &
            List<T>::Iterator<L>::operator*() {
                return * pos;
            }
    
            template <typename T>
            template <typename L>
            typename List<T>::template Iterator<L> &
            List<T>::Iterator<L>::operator++() { // prefix
                ++pos;
                return *this;
            }
    
            template <typename T>
            template <typename L>
            typename List<T>::template Iterator<L>
            List<T>::Iterator<L>::operator++(int) { //postfix
                Iterator<L> tmp = *this;
                ++(*this);
                return tmp;
            }
    
            template <typename T>
            template <typename L>
            bool
            List<T>::Iterator<L>::operator !=(const List<T>::Iterator<L> & other) const {
                return pos != other.pos;
            }
    
            template <typename T>
            template <typename L>
            bool
            List<T>::Iterator<L>::operator ==(const List<T>::Iterator<L> & other) const {
                return pos == other.pos;
            }
    
            template <typename T>
            template <typename L>
            List<T>::Iterator<L>
            List<T>::Iterator<L>::operator=(const List<T>::Iterator<L> & other) {
    
                if(this != &other){
                    pos = other.pos;
                }
    
                return *this;
            }
    
            template <typename T>
            template <typename L>
            List<T>::Iterator<L>
            List<T>::Iterator<L>::operator+(const unsigned int position){
                pos += sizeof(L*)*position;
                return *this;
    
            }
    
            template <typename T>
            template <typename L>
            List<T>::Iterator<L>
            List<T>::Iterator<L>::operator-(const unsigned int position){
                pos -= sizeof(L*)*position;
                return *this;
    
            }
    
            template <typename T>
            typename List<T>::iterator
            List<T>::begin() {
                if(size() > 0){
                    return iterator(&queue[0]);
                }
                else{
                    return end();
                }
            }
    
            template <typename T>
            typename List<T>::iterator
            List<T>::end() {
                return iterator(&queue[queue.size()]);
            }
    
            template <typename T>
            typename List<T>::const_iterator
            List<T>::begin() const {
                if(size() > 0){
                    return iterator(const_cast<T*>(&queue[0]));
                }
                else{
                    return end();
                }
            }
    
            template <typename T>
            typename List<T>::const_iterator
            List<T>::end() const {
                return iterator(const_cast<T*>(&queue[queue.size()]));
            }
    

    Ich wenn ich ein Element aus einer einelementigen Liste lösche und dann mit begin() mir einen neune Iterator hole, renne ich beim nächsten Zugriff auf den Iterator in ein seg-fault, da offenbar it != end() hier als Abbruchbedingung mist baut, also end() falsch ist. Jemand nen Tipp??? Ihr würdet mir sehr helfen.

    der Sven.



  • mach dat virtual da vorm destructor wech
    mach aus protected ein private. du willst nicht wirklich davon ableiten.
    Das Iterator-Template würde ich außerhalb von List<T> definieren.
    Was soll das const_cast da überall?!
    Wer hat dir &queue[queue.size()] erlaubt?! Darfste nich! Da fehlt auch ein ist-queue-leer-test!

    Bitte ein testbares Minimalbeispiel zeigen, was man direkt dem Compiler zum Fraß vorwerfen kann. Ich weiß z.B. nicht genau, was du da "getestet" haben willst.


  • Mod

    Was kkaw sagte. Da sind aber noch eine Menge anderer Sachen drin, die verdächtig aussehen. Du scheinst da Pointerarithmetik von Hand implementieren zu wollen:

    List<T>::Iterator<L>::operator+(const unsigned int position){
                pos += sizeof(L*)*position;
                return *this;
    
            }
    

    (und viele ähnliche Stellen)

    (L*) ist ein Pointertyp. Dessen sizeof ist hier nicht relevant. Zudem ist pos schon vom Typ L*, wenn du nun also Arithmetik mit pos durchführst, als wenn es ein int wäre, dann kommt ganz was falsches raus. Der Bezeichner "position" ist zudem höchst irreführend in dieser Funktion. Du benutzt übrigens sehr viele irreführende Bezeichner. Ich musste den Code 3x lesen um zu merken, dass deine Liste ein Vector ist.

    Da sind noch viel mehr Stellen, die mir beim Querlesen als verdächtig aufgefallen sind, aber leider kann man den Code nicht testen.



  • Morgen zusammen :),

    das sind ja viele viele Punkte. Puh, dachte nicht das es soo schlimm ist. 😞

    Also hier erst mal das Minibsp:

    http://codepad.org/mGUIClmj

    Mit meinem GCC 4.7.7 mit c++11 aus den Redhat Devtools 1.1 compiliert er fehlerfrei und ein Lauf endet im Seg-Fault, wie ich vermute halt weil begin/end falsch ist.

    Zu den anderen Punkten von kkaw:

    1. virtual Destrucktor: ich leite von der List<T> ab, also es ist nur die Subklasse. Da brauch ich doch einen virtuellen Destruktor, oder?
    2. protected und private, siehe 1)
    3. Das mit den außerhalb habe ich extra nicht gemacht, da ich so schön den Aufruf ala List<T>::iterator machen kann. Außerdem versaut es mir nicht den namespace. Oder übersehe ich hier was?
    4. Die const_casts habe ich drin, weil ich es nicht besser wußte, wie man nen const begin/end hinbekommt.
    5. Ja, also das begin/end falsch hab ich verstanden, weiß aber im Moment nicht wie ich es besser machen kann 😕
    6. Getestet hatte ich zum Beispiel einfach list.add() und dann list.remove(). So wie es nun in der main genutzt wird, wodurch der Fehler wirksam wird, hatte ich es nicht getestet.

    zu SeppJ
    7) Pointerarithmetik: Wie kann ich es besser machen?
    😎 Menge andere Verdächtige Sachen: Welche? Wie kann ich es besser machen? 😃
    9) operator+: die habe ich eigentlich nur drin, weil ich gelesen habe, dass es ein forward iterator haben muß, sonst hätte ich es weggelassen. das postion nicht die beste wahl ist, ist mir auch klar, aber ich fand keine bessere bezeichnung. threshold o.ä. ist auch nicht eindeutig in dem kontext. Das die Liste auf einem Vector basiert ist leider historisch gewachsen. Ich weiß, dass es nicht korrekt ist. Im Programm wird es auch nur als List verwendet, wobei der wahlfreie Zugriff von <vector> hier sehr nett ist, der bei <list> teuer ist. ich plane langfristig vector auch ganz rauszuschmeißen, sofern ich den nahtlosen umstieg sichern kann. habe da haste auf jeden fall recht. 😞
    10) Welche Bezeichner sind noch doof?

    Vielen Dank schonmal und ich hoffe weiter auf Eure Unterstützung! 🙂



  • Hallo nochmal,

    ich habe es nun ein wenig modifiziert und nun tut es, könnt ja mal schauen und feedback geben? wäre cool:
    http://codepad.org/VuGeNRxn

    Ein Problem habe ich aber noch. Wenn ich remove (Zeile 330 - 342) gegen folgenden Code austausche:

    template <typename T>
    typename List<T>::iterator
    List<T>::remove(const T & a) {
    
        List<T>::iterator it;
    
        it = queue.erase(std::remove(queue.begin(),
                                     queue.end(),
                                     a),
                         queue.end());
    
        return iterator(it);
    }
    

    Bekomme ich:

    main.cc: In instantiation of ‘List<T>::iterator List<T>::remove(const T&) [with T = int; List<T>::iterator = List<int>::Iterator<int>]’:
    main.cc:428:37:   required from here
    main.cc:337:5: error: no match for ‘operator=’ in ‘it = ((List<int>*)this)->List<int>::queue.std::vector<_Tp, _Alloc>::erase<int, std::allocator<int> >(std::remove<__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, int>(((List<int>*)this)->List<int>::queue.std::vector<_Tp, _Alloc>::begin<int, std::allocator<int> >(), ((List<int>*)this)->List<int>::queue.std::vector<_Tp, _Alloc>::end<int, std::allocator<int> >(), (* & a)), ((List<int>*)this)->List<int>::queue.std::vector<_Tp, _Alloc>::end<int, std::allocator<int> >())’
    main.cc:337:5: note: candidate is:
    main.cc:160:1: note: List<T>::Iterator<L> List<T>::Iterator<L>::operator=(const List<T>::Iterator<L>&) [with L = int; T = int]
    main.cc:160:1: note:   no known conversion for argument 1 from ‘std::vector<int, std::allocator<int> >::iterator {aka __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >}’ to ‘const List<int>::Iterator<int>&’
    main.cc: In instantiation of ‘List<T>::Iterator<L>::Iterator() [with L = int; T = int]’:
    main.cc:334:23:   required from ‘List<T>::iterator List<T>::remove(const T&) [with T = int; List<T>::iterator = List<int>::Iterator<int>]’
    main.cc:428:37:   required from here
    main.cc:96:11: error: invalid use of non-static data member ‘List<int>::queue’
    main.cc:103:35: error: from this location
    

    Zeilennummern siehe codepad. 😞

    Was ist da noch falsch bzw. fehlt??


  • Mod

    Lassen wir mal deine Klasse ganz weg und nehmen einen normalen vector mit deinem Hauptprogramm:

    #include <vector>
    #include <iostream>
    #include <algorithm>
    
    int
    main(int argc, char** argv) {
    
      std::vector<int> tempList;
    
      tempList.push_back(1);
    
      for (std::vector<int>::iterator it = tempList.begin(); it != tempList.end(); it++) {
        std::cerr << *it << "\n";
        if (*it == 1) {
    
          tempList.erase(std::remove(tempList.begin(),
                                     tempList.end(),
                                     *it),
                         tempList.end());
          std::cerr << "deleted\n";
          for (size_t i = 0; i < tempList.size(); i++) {
            std::cerr << tempList.at(i) << "\n";
          }
          std::cerr << "new round\n";
          it = tempList.begin();
        }//End if
      }//End for
    
      return 0;
    }
    

    Wäre dieser Code so richtig? Offensichtlich nicht, denn in Zeile 25 wird it zwar auf begin gesetzt (welches nach der ersten Runde gleich end ist), aber direkt danach wird es um 1 erhöht, wenn das it++ anschlägt. Dadurch ist dann it != end und die Schleife läuft weiter, obwohl it hinter den vector zeigt.
    Das ist erst einmal kein direktes Problem mit deiner Klasse und deinem Iterator, sondern dass du Probleme mit der Formulierung einer Schleife hast. Da mir nicht klar ist, was die Schleife überhaupt für einen Sinn hat, kann ich aber auch nicht wirklich eine Alternative vorschlagen. Reparieren könnte man es zwar halbwegs elegant, indem man while statt for benutzt, aber es sieht nicht so aus, als wüsstest du, was du mit der Schleife überhaupt genau möchtest, daher schlage ich diese Lösung nur unter Vorbehalt vor.

    Pointerarithmetik: Wie kann ich es besser machen?

    Indem du es richtig machst. 🙂
    Hast du mal nachgeschlagen, was Pointerarithmetik überhaupt ist? Dir scheint gar nicht bewusst zu sein, dass es das gibt. Im Prinzip heißt Pointerarithmetik, dass du gar nicht machen brauchst, weil alles automatisch richtig passiert.

    Menge andere Verdächtige Sachen: Welche? Wie kann ich es besser machen?

    Das war ja nur ein Beispiel, wo du selber mit Pointern rechnest von mehreren Stellen. Die Frage passt auch mit der Folgefrage

    Welche Bezeichner sind noch doof?

    zusammen. Eine kurze Kritik (nur quergelesen und Dinge, die noch nicht genannt wurden):
    -Operator<<: Warum der Stringstream?
    -Deine Default- und Kopierkonstruktoren, Zuweisungsoperatoren und Destruktoren machen effektiv alle das gleiche wie die automatisch generierten.
    -Komische Semantik von add. Klingt eher wie insert oder push_back.

    • add(const T* tArray, size_t length) -> Iteratoren statt Zeiger + Länge. Macht das gleiche, ist aber viel flexibler.
      -throw Integertyp?
      -bounce = prellen. bounds = Grenzen
      -komische Semantik von remove. Mal entfernt es bestimmte Elemente, mal alles mit einem bestimmten Wert.
      -sort: Wenn dein sort nichts spezielles leistet, wieso dann ein sort anbieten?
      -komische Semantik des Vergleichsoperators. Überall sonst ist bei dir die Reihenfolge wichtig, hier auf einmal nicht mehr.


  • Hallo SeppJ,

    erst mal riesigen Dank für deine ausführlichen Antworten! Super! 🙂

    Den Fehler in der main habe ich selber entdeckt und gefixt. Der war sehr dämlich.

    Zu deinen Kommentaren:

    Indem du es richtig machst.
    Hast du mal nachgeschlagen, was Pointerarithmetik überhaupt ist? Dir scheint gar nicht bewusst zu sein, dass es das gibt. Im Prinzip heißt Pointerarithmetik, dass du gar nicht machen brauchst, weil alles automatisch richtig passiert.

    Ja habe ich, in den alten C Tagen. 😉 Seit dem habe ich es vermieden. Ich dachte eigentlich, da gibt es was cooles C++ mäßiges, wie static_cast<int>(x) statt (int)x, was ich nicht kenne. 😉 Besser überlegen sollte man da auf jeden Fall und in der aktuellen Variante komme ich ja auch erst mal ohne aus, auch wenn ich mir dadurch nen Problem mit dem const_iterator einhandle. 😞

    Zu den Anmerkungen:

    -Operator<<: Warum der Stringstream?

    Der Code ist aus meinen richtigen Programm rausgenommen, wo der Output entweder auf den outstream geht oder auf so nen komisches DEBUG macro. Per stringstream war es einfacher beide Fälle zu behandeln, ich habs aber nun zusammengekürzt.

    -Deine Default- und Kopierkonstruktoren, Zuweisungsoperatoren und Destruktoren machen effektiv alle das gleiche wie die automatisch generierten.

    Ich dachte bisher, dass man selbst in diesen Fällen nach der Regel der goldenen 3 (jetzt wohl 5) diese immer angeben sollte, selbst wenn die automatisch generierten reichen würden. Ist dann wohl nen irrglaube.

    -Komische Semantik von add. Klingt eher wie insert oder push_back.

    Nun, in der Tat ist das hier wohl ne Ansichtssache. Ich persönlich finde, das ein insert ein konkretes einfügen an einer Stelle ist. Somit kann semantisch für mich ein insert immer nur sagen: füge x zwischen y und z ein. Ein add fügt hingegen einfach nur etwas einer Menge hinzu. Da ne Liste erst einmal nichts weiter als eine Menge ist, passt aus meinen Augen besser add statt insert. Aber dies ist wohl Geschmackssachen. Ein push_back kommt allerdings nicht in Frage, da es auf eine konkrete Implementierung verweißt, und die List-Klasse auf verschiedenen Plattformen immer gleich sein soll. Mal im Simulator, mal in der echten Welt, unabhängig ob es nun intern ein vector, nen array oder ne QList ist. Push_back würde somit dem Nutzer sagen, hey, ich bin ein vector, was unter Umständen aber gar nicht so ist.

    Wie schon erwähnt, die Klasse mutiert seit mehren Generationen. Nun will ich es besser machen. Langfristig würde ich auch gern den vector gegen was schöneres austauschen (schon wegen der Semantik), allerdings wird zumeist die list von 0..x durchlaufen, was ja ne Stärke des vectors ist. was anderes habe ich nicht gefunden.

    -add(const T* tArray, size_t length) -> Iteratoren statt Zeiger + Länge. Macht das gleiche, ist aber viel flexibler.

    Ausgetauscht. Cooler Tipp. Danke.

    -throw Integertyp?

    Nur wegen der Demo, sonst wird da ne Subklasse von exception geworfen, mit ner Fehlermeldung.

    -bounce = prellen. bounds = Grenzen

    Peinlich, gefixt.

    -komische Semantik von remove. Mal entfernt es bestimmte Elemente, mal alles mit einem bestimmten Wert.

    Nun, die List speichert im allgemeinen Instanzen eines Typs. Zum Beispiel Autos. Das remove so wie hier verwendet, soll dann auch ermöglichen, dass ich das Auto löschen kann, wenn ich nur die Fahrgestellnummer kenne und nicht das Auto an sich habe. In der Extraktion fürs Minibeispiel kommt dann sowas komisches raus.

    -sort: Wenn dein sort nichts spezielles leistet, wieso dann ein sort anbieten?

    Es wird oft verwendet und spart somit Codezeilen. Als es eingeführt wurde, war das sortieren wesentlich umständlicher als heute. Ist somit ne Art legacy code, von dem ich mich noch nicht trennen kann. Clean code mäßig von ich es lesbaren zu sagen liste sortiere dich, statt die liste selbst zu sortieren als Nutzer.

    -komische Semantik des Vergleichsoperators. Überall sonst ist bei dir die Reihenfolge wichtig, hier auf einmal nicht mehr.

    Den versteh ich nicht. Was ist da falsch?

    Aktuell habe ich versucht den Iterator einfach "durchzuschleifen" um somit das Pointer-Thema loszuwerden. Leider laufe ich somit in das Problem, dass ich nen const T im vector speichern will, was nicht erlaubt ist. Nun ist die Frage, wie kann ich einen const_iterator definieren???

    Die aktuelle Version ist hier zu finden:
    http://codepad.org/5bz7rNYy

    Beim googlen habe ich entweder nur Varianten gefunden, welche den iterator als typedef von vector::iterator definieren, oder für komplett eigene Implementierungen eine schreiben. Solche wrapper-Iteratoren habe ich noch nicht gefunden. Den vector möchte ich aber nicht rausgeben, da sonst viele den vector direkt verwenden könnten und ich dann Probleme bekomme, wenn ich den vector gegen was schöneres austausche.

    Verständlich?



  • hallo nochmal,

    ich habe mein const_iterator nun so gefixt:

    class List {
    public:
    
        template <typename L>
        class Iterator : public std::iterator<std::forward_iterator_tag, L> {
    
            typename std::vector<typename std::remove_const<L>::type>::iterator index;
    
            friend class List<T>;
    
            explicit Iterator(typename std::vector<typename std::remove_const<L>::type>::iterator it);
    
        public:
    
            Iterator();
    
            Iterator(Iterator<typename std::remove_const<L>::type > const & other);
    
            L & operator*();
    
            Iterator<L> & operator++(); // prefix
            Iterator<L> operator++(int); //postfix
    
            bool operator !=(const Iterator<L> & other) const;
            bool operator ==(const Iterator<L> & other) const;
    
            Iterator<L> operator=(const Iterator<L> & other);
            Iterator<L> operator+(const unsigned int position);
            Iterator<L> operator-(const unsigned int position);
    
        };
    
        typedef Iterator<T> iterator;
        typedef Iterator<const T> const_iterator;
    

    Kann man dies so lassen, oder sind da gröbere Fehler drin? (Ich weiß, ist nur die Signatur, aber um Platz zu sparen. 🙂 )


  • Mod

    Kann man dies so lassen, oder sind da gröbere Fehler drin?

    Warum kann man einem const_iterator keinen iterator zuweisen? (Edit: Oder geht das etwa durch den Konvertierungskonstruktor?)

    Übrigens musst du innerhalb der Definition des Klassentemplates Iterator nicht mit der Argumentenliste qualifizieren, da es der injected-class-name ist - also bspw.

    Iterator<L> operator=(const Iterator<L> & other);
    // =>
    Iterator operator=(const Iterator & other);
    


  • wo meinst? übersehe ich was?

    einen const_iterator auf nen iterator sollte doch eh nicht gehen, da ihm doch die "schreibrechte" fehlen. anders herum müßte es gehen, da man dem iterator ja rechte entzieht.


  • Mod

    Doch, funktioniert, durch den Konvertierungskonstruktor, hab's mir schon gedacht. Dabei muss aber eine Temporary erstellt werden - eigentlich übeflüssig.

    Vielleicht solltest du den Zuweisungsoperator auch umschreiben:

    #include <iostream>
    #include <iterator>
    
    template <typename L>
    class Iterator : public std::iterator<std::forward_iterator_tag, L>
    {
    public:
    
    	Iterator(){}
    
    	Iterator(Iterator<typename std::remove_const<L>::type > const & other) { std::cout << "Konvertierungs-Ctor"; }
    
    	Iterator<L> operator=(const Iterator<L> & other) { return *this; }
    };
    
    typedef Iterator<int> iterator;
    typedef Iterator<const int> const_iterator;
    
    int main()
    {
    	iterator i;
    	const_iterator i2;
    	i2 = i;
    }
    


  • wie gehts den besser?



  • sven_ schrieb:

    einen const_iterator auf nen iterator sollte doch eh nicht gehen, da ihm doch die "schreibrechte" fehlen. anders herum müßte es gehen, da man dem iterator ja rechte entzieht.

    Arcoth hat es ja auch anders herum geschrieben.
    Du musst auf die Fälle achtgeben:
    einem A einen B zuweisen
    !=
    einen A einem B zuweisen



  • Sorry jungs,

    ich raffe es einfach nicht. Wenn ich den operator<< nutzen will, fliegt mir der const_iterator um die Ohren. Wie muß das Scheißding den nun richtig aussehen?????? Ich check es einfach nicht.



  • hallo hustbaer,

    vielleicht sitz ich ja auf der leitung, aber ich checke es einfach nicht. 😞 😕


  • Mod

    sven_ schrieb:

    vielleicht sitz ich ja auf der leitung, aber ich checke es einfach nicht. 😞 😕

    Er und ich meinen:

    Einem A einen B zuweisen: A = B
    Einen A einem B zuweisen: B = A

    Und du solltest einen Zuweisungsoperator bereitstellen der es erlaubt einem const_iterator einen iterator zuzuweisen, um die Temporary zu vermeiden.



  • na salop gesagt, wen interessiert aktuell das temporary. ich schaffe es doch offensichtlich noch nicht mal korrekt nen const_iterator zu erstellen, da:

    std::cerr<<tempList<<"\n";

    massive auf die schnauze fällt. oder hängt dies damit auch zusammen.

    ich versuche mal den zuweisungsoperator zu basteln.



  • also ich bekomms leider echt nicht hin. laut meiner logik (welche bestimmt falsch ist), muß ich doch nun zwei zuweisungsoperatoren anbieten:

    operator=(const_it ...)
    operator=(it ...)

    das wäre dann, also:

    Iterator< <typename std::remove_const<L>::type > > operator=(const Iterator<typename std::remove_const<L>::type > & other);
    
    Iterator<const <typename std::remove_const<L>::type > > operator=(const Iterator<const typename std::remove_const<L>::type > & other);
    

    Der compiler sagt da aber:

    ISO C++ forbids declaration of ‘type name’ with no type [-fpermissive]
    List.h:55:71: error: template argument 1 is invalid
    

    Im Prinzip müßte es aufgrund des Templates eher außerhalb von Iterator definiert werden, da ist es aber nicht erlaubt. Also wie soll das gehen? 😕

    😞



  • Kein Wunder, wenn die Syntax falsch ist.

    Iterator< <typename std::remove_const<L>::type > >
    Iterator<const <typename std::remove_const<L>::type > >
    

    Was sollen zwei öffnende < bezwecken?



  • stimmt, passiert wohl, wenn man nicht mehr durchsieht. 😞

    War es mit den beiden zuweisungsoperatoren so gemeint:

    Iterator operator=(Iterator<typename std::remove_const<L>::type > & other) {
    
                if (this != &other) {
                    std::iterator<std::forward_iterator_tag, L>::operator=(other);
                    index = other.index;
                }
    
                return *this;
            }
    
            Iterator operator=(Iterator< const typename std::remove_const<L>::type > & other){
    
                if (this != &other) {
                    std::iterator<std::forward_iterator_tag, L>::operator=(other);
                    index = other.index;
                }
    
                return *this;
            }
    

    ???

    Der aktuelle Stand meiner Versuche wäre dann dieser:
    http://codepad.org/UaaoEnDp

    Was hierzu führt:

    main.cc: In instantiation of ‘List<T>::const_iterator List<T>::begin() const [with T = int; List<T>::const_iterator = List<int>::Iterator<const int>]’:
    main.cc:226:27:   required from ‘std::ostream& operator<<(std::ostream&, const List<T>&) [with T = int; std::ostream = std::basic_ostream<char>]’
    main.cc:454:16:   required from here
    main.cc:210:41: error: no matching function for call to ‘List<int>::Iterator<int>::Iterator(const TList&, std::vector<int, std::allocator<int> >::const_iterator)’
    main.cc:210:41: note: candidates are:
    main.cc:124:1: note: List<T>::Iterator<L>::Iterator(const List<T>::Iterator<typename std::remove_const<L>::type>&) [with L = int; T = int; typename std::remove_const<L>::type = int]
    main.cc:124:1: note:   candidate expects 1 argument, 2 provided
    main.cc:119:1: note: List<T>::Iterator<L>::Iterator(typename std::vector<typename std::remove_const<L>::type>::iterator) [with L = int; T = int; typename std::vector<typename std::remove_const<L>::type>::iterator = __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >]
    main.cc:119:1: note:   candidate expects 1 argument, 2 provided
    

Log in to reply