Gibts ne Typenerkennung fuer Iteratoren ???



  • also gut, aber das eine mal eben iterator, das andere mal reverse_iterator, und
    diesen Unterschied muss ich doch in der Schleife durch den Container im Falle eines
    reverse_iterators mit nem break quitieren.
    Da hab ich u.U. ja auch ein generelles Verstaendnisproblem, von wegen zur
    Compile-Zeit bzw zur Laufzeit:
    Wird denn die template-Funktion fuer verschiedene Aufrufe anders compiliert?
    Dann ist ja ne template-Funktion nur'n hack fuer'n programisten, und compiliert
    gibt's die Funktion dann sooft, wie sie aufgerufen wird??
    Diese Antworten wuerden mir wirklich weiter helfen, so zum Verstaednis eben...

    SF



  • Die template-Funktion wird mehrfach instanziiert, für jede Kombination von Typen mindestens einmal.

    Wenn Du

    Funktion<int>(); schreibst, dann wird Funktion mit dem Typ int instanziiert und aufgerufen. Das instanziieren passiert zur Compilezeit.
    Schreibst Du jetzt Funktion<float> dann wird eine neue Funktion generiert mit float als Parameter. usw.
    Es wird nicht die gleiche Funktion wiederverwendet. Das template ist eine Vorlage, sozusagen eine Bauanleitung für Klassen/Funktionen bei denen noch ein paar Sachen offen gelassen wurden (die template-Parameter). Wenn Du die jetzt angibst, dann werden die entsprechenden Funktionen generiert. Aber dieses einfügen kann nur zur Compilezeit geschehen. Es gibt keine Syntax die es ermöglicht das erst zur Laufzeit zu tun, ginge ja auch nicht.

    MfG Jester



  • Ok, das hab ich nun verstanden; ist es denn in diesem Fall besser, nur EINE
    template-Funktion zu benutzen, in der ich dann zur "Compile-Zeit" im Falle eines
    reverse_iterators bei Fund die Schleife durch den entsprechenden Container
    abbreche, oder eine "normale" ueberladene Funktion zu schreiben, die dann aber
    doppelt so oft geschrieben werden muss, wie es verschiedene Container bzw.
    verschiedene Key-types gibt?
    Was ist der bessere oder sinnvollere Programmierweg?

    SF



  • Die Funktion als template zu schreiben ist natürlich sinnvoll, Du sagst ja selbst, man muß die Funktion nicht mehrmals schreiben. Und mit den oben gezeigten Tricks von davie kann man die Funktionen sogar abhängig vom Parameter leicht modifizieren.

    templates sind oft gut geeignet wenn man eine Funktion mehrmals schreiben müßte, jedesmal nur mit kleinen Unterschieden.



  • Na dann war ich immerhin schon aufm richtigen Weg 🕶
    Jetzt muss ich dann nur noch davies methode zu Erennung des reverse_iterators
    begreifen, aber heut nicht mehr.
    Danke soweit mal, frag dann wieder wenn ich richtig vor meinem Code sitz und's
    nich mehr blick 😞

    Schoenen Abend
    SF



  • Nabend,

    hab's jetzt folgendermasen geloest:

    template <typename K, typename S>
            inline bool REV_IT(std::map<K,S>::iterator it){
                return false;
            }
    
        template <typename K, typename S>
            inline bool REV_IT(std::multimap<K,S>::iterator it){
                return false;
            }
    
        template <typename K, typename S>
            inline bool REV_IT(std::map<K,S>::reverse_iterator it) {
               return true;
            }
    
        template <typename K, typename S>
            inline bool REV_IT(std::multimap<K,S>::reverse_iterator it) {
               return true;
            }
    // und der Aufruf:
        template<typename InIt, typename K, typename S>
            InIt find_in(InIt BEG, InIt FIN, const S LAST_OPEN){
                InIt RESULT = FIN;
                while(BEG != FIN){
                        if(strcmp((*BEG).second.c_str(), LAST_OPEN.c_str()) == 0){
                            RESULT = BEG;
                            if(REV_IT<K,S>(BEG) == true)
                                break;
                        }
                        ++BEG;
                }   
                return RESULT;
            }
    

    Mit davie's Vorschlag:

    template <class It> 
    inline bool is_reverse (It) { return false; } 
    
    template <class It> 
    inline bool is_reverse (reverse_iterator<It>) { return true; }
    

    gab's nen Parse Error vor dem ">"-Zeichen in der hier letzten Zeile. War denn
    sein Vorschlag nur schematisch, oder fehlt mir fuer das Argument: (reverse_iterator<It>)
    was includiertes (und das Verstaendnis 😕 ).

    Trotzdem funktioniert die o.g. ueberladene Funktion REV_IT, und wenn ich's richtig
    verstanden hab, muesste ich sie bezueglich map und multimap garnicht ueberladen, da
    sich die Iteratoren der sehr aehnlichen Container vermutlich von ihrer Struktur her
    nicht unterscheiden?

    Vielen Dank fuer alle Tips und Erklaerungen 🙂

    SF



  • Nimm mal noch ein

    #include<iterator>

    dazu. und denk dran, daß das reverse_iterator-template in std íst.
    Eine ganz waschechte Compile-time Lösung ist da übrigens nicht, aber die Entscheidung wird wahrscheinlich dann rausoptimiert.

    MfG Jester



  • Hallo Jester,

    das war der genau richtige Tip(std::reverse_iterator), somit funktioniert es auf alle Faelle ohne dass fuer map und multimap ueberladen werden muss. 👍

    Was meinst denn mit

    Jester schrieb:

    ...aber die Entscheidung wird wahrscheinlich dann rausoptimiert.

    Dass der Compiler dieses macht 😕

    Danke nochmal, schoenen Abend

    SF



  • na, bist du ein Stück weiter gekommen. Freud mich für dich.

    Habe mal'ne Frage zur Funktion find_in

    also angenommen (position eintrag)
    0 A, 1 B,2 C, 3 C, 4 D, 5 D, 6 E sind in der Mapppe.
    suche C vorwärts würde position 3 ergeben
    suche C rückwärts würde position 3 ergeben

    Also soll die Funktion den letzten in vorwärts Richtung finden
    und den ersten in rückwärts Richtung.

    hätte da noch ein Vorschlag zu machen 🙂
    partielle Spezialisierung von Templates
    Na ja, guck es dir an vielleicht hilft es ja

    template<class C>  C find_in(C first,C last,const string& s)
    {
    	std::cout<<"basis"<<std::endl;
    	return first;
    }
    template<class C> C::iterator find_in(C::iterator first,C::iterator last,const string& s)
    {
    	std::cout<<"iterator"<<std::endl;
    
    	C::iterator RetIter;
    	while(first!=last)
    	{
    		if(first->second==s)
    			RetIter=first;
    
    		first++;
    	}
    	return RetIter;
    }
    template<class C> C::reverse_iterator find_in(C::reverse_iterator first,C::reverse_iterator last,const string& s)
    {
    	std::cout<<"reverse_iterator"<<std::endl;
    
    	while(first!=last)
    	{
    		if(first->second==s)
    			return first;
    
    		first++;
    	}
    	return first;
    } 
    typedef std::multimap<int,string> MINT;
    
    int main(int argc, char* argv[])
    {
    	MINT m_Int;
    	MINT::reverse_iterator rIter;
    	MINT::iterator Iter;
    
    	m_Int.insert(MINT::value_type(0,"a"));
    	m_Int.insert(MINT::value_type(1,"b"));
    	m_Int.insert(MINT::value_type(2,"c"));
    	m_Int.insert(MINT::value_type(3,"c"));
    	m_Int.insert(MINT::value_type(4,"d"));
    	m_Int.insert(MINT::value_type(5,"d"));
    	m_Int.insert(MINT::value_type(6,"e"));
    
    	Iter=find_in<MINT>(m_Int.begin(),m_Int.end(),"c");
    	rIter=find_in<MINT>(m_Int.rbegin(),m_Int.rend(),"c");
    
    	if(Iter!=m_Int.end())
    	std::cout<<Iter->first<<Iter->second<<std::endl;
    	if(rIter!=m_Int.rend())
    	std::cout<<rIter->first<<rIter->second<<std::endl;
    return 0;
    }
    


  • hi,

    idefix schrieb:

    Habe mal'ne Frage zur Funktion find_in

    also angenommen (position eintrag)
    0 A, 1 B,2 C, 3 C, 4 D, 5 D, 6 E sind in der Mapppe.
    suche C vorwärts würde position 3 ergeben
    suche C rückwärts würde position 3 ergeben

    Also soll die Funktion den letzten in vorwärts Richtung finden
    und den ersten in rückwärts Richtung.

    Ja, die Funktion soll in jedem Fall die letzte Uebereinstimmung (von vorne her gesehen) finden;
    Aber vielleicht hab ich ja da mal wieder ein grundlegendes Verstaendisproblem, ich dachte, dass bei der Suche mit nem iterator von vorne, und mit nem reverse_iterator eben von hinten "gesucht" wird, so dass die iterator-Variante bei Deinem Beispiel die "Zeile:" 3 C, und bei der reverse_iterator-Variante die "Zeile:" 2 C zurueckgeben taete, wohlbemerkt ohne die break-Version bei der reverse_iterator-Variante.

    Bei Deinem Vorschlag mit der ueberladenen Version wird bei der reverse_iterator-Variante schon beim ersten Fund returned, was (eigentlich sollte die Funktion
    find_last_in(X,Y,S) statt find_in(X,Y,S) heissen) dann latuernich genauso den gewuenschten Effekt erzielt.

    Ab hier wird's meines Erachtens philosophisch, bzw. es geht dann halt um Programmierstil. Zum Vergleich hier nochmal meine komplette Version:

    template <class It>
         inline bool REV_IT(It){
             return false;
         }
    
    template <class It>
         inline bool REV_IT(std::reverse_iterator<It>) {
             return true;
         }
    
    template<typename InIt, typename K, typename S>
         InIt find_in(InIt BEG, InIt FIN, const S LAST_OPEN){
         InIt RESULT = FIN;
         while(BEG != FIN){
             if(strcmp((*BEG).second.c_str(), LAST_OPEN.c_str()) == 0){
                 RESULT = BEG;
                 if(REV_IT(BEG))
                     break;
             }
             ++BEG;
         }
         return RESULT;
    }
    

    21 zu 27 Zeilen, oder 485 zu 633 Bytes 😉
    Aber Spass beiseite, ich bin latuernich als Anfaenger auch an einer Bewertung der Programmierstils interessiert, hier in meinem Kaemmerchen die Dinge wertfrei nur so zu laufen zu bekommen kann's ja auch nicht sein, und Bytes bzw. Zeilen zu zaehlen scheint mir doch auch ein wenig zu lapidar.

    Also bitte, keine Scheu vor Bewertung...

    solong
    SF


Anmelden zum Antworten