Iterator begin und end falsch


  • 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
    

  • Mod

    Zeig doch mal Zeile 210. Du versuchst anscheinend einen Iterator mit zwei Argumenten zu initialisieren (einer TList und einem const_iterator), aber dein Iterator kennt nur zwei Konstruktoren, von denen beide jeweils einen Parameter von einem Iteratortyp erwarten.



  • Hallo zusammen,

    da ich gestern durch das Spiel ein wenig abgelenkt war erst heute hier die Antwort. 🙂

    template <typename T>
    std::ostream&
    operator<<(std::ostream & out, const List<T> & l) {
    
        out << "[";
    
        typename List<T>::const_iterator e;
        for ( e = l.begin(); e != l.end(); e++) {
            out << (*e);
        }
        out << "]";
        return out;
    }
    

    Die Zeile 217 ist die Zeile mit den for-Schleifen-Kopf:

    main.cc: In instantiation of ‘std::ostream& operator<<(std::ostream&, const List<T>&) [with T = int; std::ostream = std::basic_ostream<char>]’:
    main.cc:458:18:   required from here
    main.cc:217:24: error: no match for ‘operator=’ in ‘e = (& l)->List<T>::begin<int>()’
    main.cc:217:24: note: candidates are:
    main.cc:143:1: note: List<T>::Iterator<L> List<T>::Iterator<L>::operator=(List<T>::Iterator<typename std::remove_const<L>::type>&) [with L = const int; T = int; typename std::remove_const<L>::type = int]
    main.cc:143:1: note:   no known conversion for argument 1 from ‘List<int>::const_iterator {aka List<int>::Iterator<const int>}’ to ‘List<int>::Iterator<int>&’
    main.cc:156:1: note: List<T>::Iterator<L> List<T>::Iterator<L>::operator=(List<T>::Iterator<const typename std::remove_const<L>::type>&) [with L = const int; T = int; typename std::remove_const<L>::type = int]
    main.cc:156:1: note:   no known conversion for argument 1 from ‘List<int>::const_iterator {aka List<int>::Iterator<const int>}’ to ‘List<int>::Iterator<const int>&’
    

    Die Konstruktoren sind:

    template <typename T>
    template <typename L>
    List<T>::Iterator<L>::Iterator(){
    }
    
    template <typename T>
    template <typename L>
    List<T>::Iterator<L>::Iterator(typename std::vector<typename std::remove_const<L>::type>::iterator it) : index(it) {
    }
    
    template <typename T>
    template <typename L>
    List<T>::Iterator<L>::Iterator(Iterator< typename std::remove_const<L>::type > const & other) : index(other.index) {
    }
    

    Der vollständige Code steht hier: http://codepad.org/SwPgqGmi


  • Mod

    operator=(List<T>::Iterator<typename std::remove_const<L>::type>&)
    

    Faellt dir nichts auf an dieser Zeile? Fehlt fa nicht irgendwo ein const ?



  • Ok, da war noch ein wenig alter Schrott drin, und das const fehlte in der Tat. Ein Schritt weiter, hoffe ich.

    Aktueller Stand: http://codepad.org/8GnALiZN

    So wie ich es sehe, ist das Problem hier:

    template <typename T>
    typename List<T>::const_iterator
    List<T>
    ::begin() const {
        return iterator(queue.begin());
    }
    

    Hier hole ich von queue einen const_iterator, und will ihn auf einen iterator legen. Deswegen sagt er:

    main.cc:204:34: error: no matching function for call to ‘List<int>::Iterator<int>::Iterator(std::vector<int, std::allocator<int> >::const_iterator)’
    

    Kommt man an der Stelle überhaupt weiter, oder muß man zu Tricks wie diesen hier greifen: http://www.sj-vs.net/c-implementing-const_iterator-and-non-const-iterator-without-code-duplication/

    ?? Ich hasse Iteratoren. 😉



  • Hallo zusammen,

    also nun habe ich eine Version, welche funktioniert. 😃
    Hier anzuschauen, bei Interesse: http://codepad.org/yiB048WD (Feedback wie immer willkommen).

    Ich habe dazu ein wenig bei Herrn Stroustrup geschaut. Die Version, wie ich es eigentlich wollte, ein Delegate-Iterator, war selbst mit seinen Beispiel-Code nicht compilierfähig. Aber ne Idee habe ich bekommen. So ist es vielleicht nicht die effizientest Variante, aber geht immerhin. Ich hoffe es sind keine weiteren Fehler drin.

    Eine Frage hätte ich noch. Ich habe ja ne Funktion add(), welche zwei Iteratoren akzeptiert. Nun habe ich festgestellt, dass diese nicht so richtig mit den std::iteratoren zusammenarbeitet. Also ein Aufruf:

    List<int> tempList;
     std::vector<std::string> a;
     tempList.add(a.begin(), a.end());
    

    ergibt:

    main.cc:393:36: error: no matching function for call to ‘List<int>::add(std::vector<std::basic_string<char> >::iterator, std::vector<std::basic_string<char> >::iterator)’
    main.cc:393:36: note: candidates are:
    main.cc:212:1: note: List<T>& List<T>::add(const T&) [with T = int]
    main.cc:212:1: note:   candidate expects 1 argument, 2 provided
    main.cc:221:1: note: List<T>& List<T>::add(List<T>::iterator, List<T>::iterator) [with T = int; List<T>::iterator = List<int>::Iterator<int>]
    main.cc:221:1: note:   no known conversion for argument 1 from ‘std::vector<std::basic_string<char> >::iterator {aka __gnu_cxx::__normal_iterator<std::basic_string<char>*, std::vector<std::basic_string<char> > >}’ to ‘List<int>::iterator {aka List<int>::Iterator<int>}’
    

    Da noch nen Tip für mich???

    Ansonsten erst mal riesen dank für Eure super Hilfe!!!!!! 🙂

    sven_


  • Mod

    Du musst lernen, solche Fehlermeldungen zu lesen. Es steht schon alles erklaert in der Meldung. Es sieht bloss komplizierter aus, als es ist, wegen der Templates. Da hilft es, den ganzen Templatekram einfach erst einmal zu ignorieren:

    main.cc:393:36: error: no matching function for call to ‘List<int>::add(std::vector<std::basic_string<char> >::iterator, std::vector<std::basic_string<char> >::iterator)’
    

    ➡

    main.cc:393:36: error: no matching function for call to ‘List<int>::add(Blah, Blah)’
    

    (mit Blah = std::vector<std::basic_string<char> >::iterator)
    Aha, es gibt also keine passende Memberfunktion add von List<int>, so wie sie in Zeile 393 benutzt wird.

    main.cc:393:36: note: candidates are:
    

    Aber es gibt andere List<int>::add(), die nicht ganz passen:

    main.cc:212:1: note: List<T>& List<T>::add(const T&) [with T = int]
    main.cc:212:1: note:   candidate expects 1 argument, 2 provided
    

    Es gibt ein add, welches ein const int& erwartet. Klar passt dieses nicht, da es nur 1 Argument nimmt, anstatt 2. Aber es gibt noch einen anderen Kandidaten:

    main.cc:221:1: note: List<T>& List<T>::add(List<T>::iterator, List<T>::iterator) [with T = int; List<T>::iterator = List<int>::Iterator<int>]
    main.cc:221:1: note:   no known conversion for argument 1 from ‘std::vector<std::basic_string<char> >::iterator {aka __gnu_cxx::__normal_iterator<std::basic_string<char>*, std::vector<std::basic_string<char> > >}’ to ‘List<int>::iterator {aka List<int>::Iterator<int>}’
    

    😮 Wieder erst einmal vereinfachen:

    main.cc:221:1: note: List<T>& List<T>::add(Blupp, Blupp) 
    main.cc:221:1: note:   no known conversion for argument 1 from ‘Blah’ to ‘Blupp’
    

    Das ist doch schon verstaendlicher. Wir haben die passende Argumentenzahl, aber die Typen passen nicht. Jetzt koennen wir genauer auf die Typen gucken. Das 'Blupp' hier ist List<T>::iterator oder, wenn man alle typedefs usw. auswertet, dann bekommt man das was der Compiler in die eckigen Klammern am Ende geschrieben hat: List<T>::iterator = List<int>::Iterator<int>]. Das add erwartet also 2x List<int>::Iterator<int>, also deinen eigenen Iteratortypen.

    Was ist das Blah? std::vector<std::basic_string<char> >::iterator. Wir sehen jetzt schon, dass das nicht passt, da das der Iteratortyp des STL-vectors ist, nicht dein List-Iterator. Falls das nocht nicht gereicht haette, hat uns der Compiler wieder in Klammern gesagt, was das fuer ein Typ ist, wenn man lles bis zum Ende auswertet: __gnu_cxx::__normal_iterator<std::basic_string<char>*, std::vector<std::basic_string<char> > >
    Daraus koennen wir nicht mehr viel ablesen, das sind nur Details, wie der vector-Iterator intern funktioniert. Wir haben oben ja schon gesehen, was falsch ist.

    P.S.: Zusammenfassung: Du benutzt vector-Iteraoren, wo deine Funktionen deine eigenen Iteratoren erwarten. Du hast keine Konvertierungsfunktion, um einen deiner eigenen Iteratoren aus einem vector-Iterator zu erzeugen (sofern dies ueberhaupt Sinn macht).
    P.P.S.: Deine add-Funktion mit 2 Parametern soll wahrscheinlich ein Template sein. Sie nimmt nicht deine Iteratoren, sondern alle moeglichen Iteratoren. Es soltle dem add schliesslich egal sein, woher die Daten kommen. Siehe die ganzen Funktionen der STL, die das so machen. Z.B.:
    http://www.cplusplus.com/reference/vector/vector/insert/
    Da gibt es die Ueberladung

    template <class InputIterator>
        void insert (iterator position, InputIterator first, InputIterator last);
    

    So soll wahrscheinlich auch dein add aussehen. Diese Muster gibt es an ganz vielen Stellen und du solltest es auch benutzen. So kann man alle moeglivchen Objekte benutzen, sie muessen sich bloss iteratorartig verhalten. Das heisst, du kannst einen STL-Vector ohne Probleme mit Zeigern (Iteratoren sind verallgemeinerte Zeiger), Iteratoren aus anderen STL-containern, oder auch problemlos mit deinem eigenen List-Iterator fuettern. Das insert interessiert hier bloss, dass man den Iterator derefenzieren, kopieren, verlgeichen und mittels ++ erhoehen kann (das wird durch den Begriff "Inputiterator" ausgedrueckt).



  • Hallo SeppJ,

    man, die Doku zu vector habe ich gestern gelesen, ich habe an eine Konvertierung gedacht, statt einfach die Schnittstelle nachzubauen. Echt dumm. 😉

    Nun bin ich dabei, habe aber ne komische Frage:

    Laut

    http://www.cplusplus.com/reference/vector/vector/insert/

    soll insert einen iterator zurückgeben.

    template <class InputIterator>
    iterator insert (const_iterator position, InputIterator first, InputIterator last);
    

    Bei mir sagt aber die stl_vector:

    template<typename _InputIterator>
            void
            insert(iterator __position, _InputIterator __first,
    	       _InputIterator __last)
            {
    	  // Check whether it's an integral type.  If so, it's not an iterator.
    	  typedef typename std::__is_integer<_InputIterator>::__type _Integral;
    	  _M_insert_dispatch(__position, __first, __last, _Integral());
    	}
    

    Habe ich da ne falsche Version??? Nutze die Redhat Devtools 1.1 mit GCC 477 und C++11.




Anmelden zum Antworten