Gibts ne Typenerkennung fuer Iteratoren ???
-
moin,
habn template geschrieben, dass in std::map und std::multimap das letzte
Auftreten (typename S) im X.second eines uebergebenen Wertes (auch typename S)
ermittelt. Uebergabe ist folgende:template<typename InIt, typename K, typename S> InIt find_in(InIt BEG, InIt FIN, const S LAST_OPEN)
wobei InIt sowohl ein Iteraror als auch ein Reverse_Iterator sein kann.
Beim Reverse_Iterator habe ich nur das Problem, dass die Schleife bei Fund
abgebrochen weden muss (letzter Fund), beim Iterator aber nicht.
Dazu sollte ich eben an der Stelle wissen, um welchen Iterator es sich handelt.
typeid(InIt) schein nicht zu gehn, vielleicht hab ich's aber auch nur falsch angegangen...SF
-
zur laufzeit willst du feststellen, ob dein iterator ein reverse iterator ist?
das geht nicht besonders gut über typeid, da dein reverse_iterator vom normalen iterator abhängt, der von dem typ des containers abhängt. das simpelste und unsicherste mit rtti wäretemplate <class It> void foo (It it) { if (strstr(typeid(It).name(), "reverse")) { cout << "It ist wahrscheinlich ein reverse-iterator!\n"; } else { cout << "It ist wahrscheinlich kein reverse-iterator.\n"; } }
aber dir genügt wahrscheinlich eine compile-time lösung:
template <class It> void foo (It it) { cout << "It ist ein normaler iterator.\n"; } template <class It> void foo (reverse_iterator<It> it) { cout << "foo mit einem reverse-iterator aufgerufen!\n"; }
-
hi,
die compile-time-Loesung reicht leider nicht, da es wie gesagt in einer
template-Funktion mal ein iterator, und mal ein reverse_iterator sein kannDer Vorschlag:
if (strstr(typeid(It).name(), "reverse"))
klingt zwar recht nett, aber ich hab folgendes mal versucht,
const char* AKT = typeid(InIt).name();
naja, da kam dann IMMER:
AKT = 0x432bcc "St16reverse_iteratorSt17_Rb_tree_iteratorISt4pairKjSsERS3_PS3_EE
bei raus, egal ob ein iterator oder ein reverse_iterator uebgergeben wurde,
uebrigens das gleiche wie beim Vergleichswert:const char* REV = typeid(std::map<K,S>::reverse_iterator).name();
Man muss ja nich immer alles verstehn
Jetzt haeng ich die Sache eh fuer ne Woche ann Nagel, und dann mal guggn.
Trotzdem Danke
SF
-
Segmentation Faulter schrieb:
die compile-time-Loesung reicht leider nicht, da es wie gesagt in einer
template-Funktion mal ein iterator, und mal ein reverse_iterator sein kann? zeig mal mehr code!
-
Segmentation Faulter schrieb:
die compile-time-Loesung reicht leider nicht, da es wie gesagt in einer
template-Funktion mal ein iterator, und mal ein reverse_iterator sein kannich glaube da irs du dich, denn templates werden auch zu compilier zeit instanziert.
davie's compilier-zeit lösung sollte hier passen
-
davie schrieb:
? zeig mal mehr code!
ok, hier die template-Funktion find_in() [sollte eigentlich find_last_in() heissen]:
template<typename InIt, typename K, typename S> InIt find_in(InIt BEG, InIt FIN, const S LAST_OPEN){ InIt RESULT = FIN; //type_info Tests const char* AKT = typeid(InIt).name(); const char* REV = typeid(std::map<K,S>::reverse_iterator).name(); //type_info Tests END while(BEG != FIN){ if(strcmp((*BEG).second.c_str(), LAST_OPEN.c_str()) == 0) RESULT = BEG; // hier sollte im Fall von reverse_iterator ein break; rein ++BEG; } return RESULT; }
Gerard schrieb:
ich glaube da irs du dich, denn templates werden auch zu compilier zeit instanziert.
davie's compilier-zeit lösung sollte hier passenhmm, schon, aber der o.g. break sollte beim reverse_iterator schon rein, da
sonst ein reverse_iterator auf das erste Vorkommen anstatt des letzten zurueckgegeben wird, oder hab ich da jetzt nen Denkfehler?SF
-
bei dir steht doch eh schon zur Compilezeit fest, welchen Typ der iterator hat.
Wie wär's mit einemtemplate <class It> inline bool is_reverse (It) { return false; } template <class It> inline bool is_reverse (reverse_iterator<It>) { return true; }
oder
template <class T> struct IsReverse { static const bool value = false; }; template <class T> struct IsReverse <reverse_iterator<T> > { static const bool value = true; };
für ein
if (is_reverse(iterator)) { //bzw ein if (IsReverse(IT)) {
wozu verwendest du überhaupt templates? du hast es doch hauptsächlich auf map iteratoren abgesehen.
-
davie schrieb:
bei dir steht doch eh schon zur Compilezeit fest, welchen Typ der iterator hat.
noe, tut's net, ich kann's ja mit beiden folgenden Argumenten aufrufen:
std::map<std::size_t,string>::iterator ERGEBNIS; ERGEBNIS = find_in(map.begin(), map.end(), DieserString); // oder std::map<std::size_t,string>::reverse_iterator R_ERGEBNIS; R_ERGEBNIS = find_in(map.rbegin(), map.rend(), DieserString);
davie schrieb:
wozu verwendest du überhaupt templates? du hast es doch hauptsächlich auf map iteratoren abgesehen.
Weil es auch eine MultiMap, und der Key Typ ein anderer sein kann:
std::multimap<unsigned long,string>::iterator ERGEBNIS; ERGEBNIS = find_in(multimap.begin(), multimap.end(), DieserString); // oder std::multimap<unsigned long,string>::reverse_iterator R_ERGEBNIS; R_ERGEBNIS = find_in(multimap.rbegin(), multimap.rend(), DieserString);
Bei den Beispielen mit dem
struct IsReverse { static const bool value = false; };
versteh versteh ich jetzt den Sinn nicht so ganz (liegt aber eher an mir...)
Soll das erkennen, ob iterator oder reverse_iterator?SF
-
Segmentation Faulter schrieb:
davie schrieb:
bei dir steht doch eh schon zur Compilezeit fest, welchen Typ der iterator hat.
noe, tut's net, ich kann's ja mit beiden folgenden Argumenten aufrufen:
[cpp]
std::mapstd::size_t,string::iterator ERGEBNIS;
ERGEBNIS = find_in(map.begin(), map.end(), DieserString);
// oder
std::mapstd::size\_t,string::reverse_iterator R_ERGEBNIS;
R_ERGEBNIS = find_in(map.rbegin(), map.rend(), DieserString);Und jetzt beantworte folgende Frage: Wenn das in Deinem Source steht, ist dann zur Compile-Zeit festgelegt oder nicht?
-
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 blickSchoenen 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 ergebenAlso 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 jatemplate<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 ergebenAlso 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