Schwierigkeiten mit templates



  • ja, wobei ich die funktion mit dem string als template spezialisieren würde, was Sone in seinem beitrag nicht gemacht hat

    mit änderung:

    template<typename T>
    std::istream& readFrom(std::istream& is, T & toread)
    {
        return is >> toread;
    }
    
    template<>
    std::istream& readFrom(std::istream& is, std::string & toread)
    {
        return std::getline(is, toread);
    }
    

    nicht dass dann probleme bei überladung oder überdeckung gibt...



  • Skym0sh0 schrieb:

    template<>
    std::istream& readFrom(std::istream& is, std::string & toread)
    {
    return std::getline(is, toread);
    }
    [/cpp]

    nicht dass dann probleme bei überladung oder überdeckung gibt...

    Deine Version ist so eigentlich falsch.

    template<>
    std::istream& readFrom<std::string>(std::istream& is, std::string & toread)
    {
        return std::getline(is, toread);
    }
    

    Und meine ist vollkommen korrekt und leichter zu lesen, denn es ist eine Überladung; für den Compiler stehen non-template functions an erster Stelle, danach kommen erst Template-Funktionen.

    Außerdem kennt jeder die Regel: Templatefunktions-Spezialisierungen sind schlecht, sie überladen nicht.



  • ..ui..da komm ich so langsam nicht mehr mit.

    Könnt ihr das vielleicht näher erklären..? ..oder mir was zu lesen geben..? 😃

    Es geht um den Unterschied zwischen

    std::istream& readFrom<std::string>(std::istream& is, std::string & toread)
    

    und

    std::istream& readFrom(std::istream& is, std::string & toread)
    

    oder..?

    Mal so nebenbei, warum ist mein eingebetteter Code eigentlich nur schwarz/weiß..? 😮 😉



  • jetzt in den letzten beispielen hast du keine schlüsselworte und nur die werden farblich herausgehoben, bei anderen code snippets von dir hattest du Code statt Cpp tags verwendet

    ok, mit den templates komme ich langsam auch nicht mehr so mit.

    ich, mit meiner intuition, würde das template so schreiben wie vorgeschlagen. und es dann für std::string weiter spezialisieren

    ich habs auch grad mal getestet (VC2010 unter Win7 64), da klappt sowohl die überladung neben dem template und der spezialisierung

    #include <iostream>
    
    template<typename T>
    T maximum(T const& a, T const& b) //template
    {
    	return a<=b ? b : a;
    }
    
    template<>
    float maximum<float>(float const& a, float const& b) //spezialisiertes template
    // oder 
    // float maximum(float const& a, float const& b)  geht auch!
    {
    	std::cout << "Template Spez" << std::endl;
    	if ( a < b )
    		return b;
    	else
    		return a;
    }
    
    float maximum(float const& a, float const& b) // normale funktion
    {
    	std::cout << "Non-Template" << std::endl;
    	if ( a < b )
    		return b;
    	else
    		return a;
    }
    
    int main(int argc, char * argv[])
    {
    	std::cout << maximum(4355.0f, 7.0f) << std::endl; // ruft die normale funktion auf
            std::cout << maximum<float>(4355.0f, 7.0f) << std::endl; // ruft die template spez auf
            std::cout << maximum(4355.0, 7.0) << std::endl; // ruft maximum<double> auf, also das template
    
    	return 0x0;
    }
    


  • template <typename T1, typename T2>
    auto max(T1 t1, T2 t2) -> decltype(t1 > t2 ? t1 : t2)
    {
        return t1 > t2 ? t1 : t2;
    }
    


  • hehe^^

    genausowas meine ich, das kommt raus wenn wer was sagt, der ahnung hat 😃



  • Kellerautomat schrieb:

    template <typename T1, typename T2>
    auto max(T1 t1, T2 t2) -> decltype(t1 > t2 ? t1 : t2)
    {
        return t1 > t2 ? t1 : t2;
    }
    

    Wie kann das überhaupt für nicht konstante Ausdrücke kompilieren (tut es, aber wieso)? 😕



  • Kellerautomat schrieb:

    template <typename T1, typename T2>
    auto max(T1 t1, T2 t2) -> decltype(t1 > t2 ? t1 : t2)
    {
        return t1 > t2 ? t1 : t2;
    }
    

    Tja, nein; obwohl das kompiliert wird, ist es eigentlich Schwachsinn.
    Der Rückgabewert der Funktion ist immer gleich (edit also bei gleichen Template-Parametern).

    Ist wohl ein Compilerbug.



  • Wieso sollte das nicht funktionieren?
    PS:
    decltype ist wie sizeof
    der wert von t1/t2 wird nicht evaluiert - nur der Ausdruck wird auf seinen Typ hin überprüft.
    PPS:
    bei int und double wird ja nicht manchmal int und manchmal double returned sondern immer double.



  • Shade Of Mine schrieb:

    bei int und double wird ja nicht manchmal int und manchmal double returned sondern immer double.

    Ach, da wird einfach direkt wie sizeof behandelt? Ist mir aufgefallen. Aber ich dachte, dass wär' ja bescheuert- ich meine, wenn man t1 < t2 schreibt dann erwarte ich dass das entsprechend ausgewertet wird... 😕

    Aber wenn nur die Größen der Typen behandelt werden, dann macht die Funktion keinen Sinn, es sei denn, es soll einfach der größere Typ zurückgegeben werden.



  • Sone schrieb:

    Shade Of Mine schrieb:

    bei int und double wird ja nicht manchmal int und manchmal double returned sondern immer double.

    Ach, da wird einfach direkt wie sizeof behandelt? Ist mir aufgefallen. Aber ich dachte, dass wär' ja bescheuert- ich meine, wenn man t1 < t2 schreibt dann erwarte ich dass das entsprechend ausgewertet wird... 😕

    Wird es ja auch - aber eben nicht vom Wert her.
    Bei sizeof wird ja auch nicht der Ausdruck auf den Wert aufgelöst, sondern auf den Typ(und dann größe). decltype liefert dir den Typ eines Ausdrucks.

    decltype(5*5) würde dir ja auch nicht 10 liefern sondern int 🙂



  • Bevor ich eine genauere Erklärung gebe, möchte ich dir eine Frage stellen. Vielleicht hilft dir das, zu verstehen, wie mein max funktioniert.

    int a = 2, b = 3;
    double c = 4., d = 1.;
    
    auto e = a > c ? a : c;
    auto f = b > d ? b : d;
    

    Von welchem Typ sind e und f? 😉



  • double

    weil das muss zur compilezeit ausgewertet werden, aber der ausdruck selbst wird nicht unbedingt (kann duch optimierungen oder sowas schon) ausgewertet. sprich der compiler sucht nach einem kompromiss, was für beides geht. und da ein int implizit nach double castable ist ---> double



  • War eigentlich an Sone gerichtet, hätte ich dazuschreiben sollen. Aber ja, das ist korrekt.



  • ok, weil ich wusste es auch nicht bestimmtheit und wollte es mal testen 😉

    kann man in dem forum so ne art spoiler funktion nutzen?


  • Mod

    Skym0sh0 schrieb:

    kann man in dem forum so ne art spoiler funktion nutzen?

    Nein, das wäre in einem Programmierfachforum keine häufig genutzte Funktion. Du kannst so etwas emulieren, indem du einen Link zu Pastebin, ideone oder ähnlichem benutzt, dem ein Leser dann optional folgen kann oder nicht.



  • Skym0sh0 schrieb:

    kann man in dem forum so ne art spoiler funktion nutzen?

    rot13 verschlüsseln 😉
    wir sind hier unter programmierern



  • Ich hab es schon durch Shades Beitrag verstanden. Ich wusste auch schon, dass die Ausdrücke nicht ausgewertet werden :), denn auch ich verwende decltype() oft. Nur, dachte ich, ist es so, dass hier entschieden wird, welcher Typ zurückgegeben wird, anhand der Werte der Variablen 😃

    Wenn ich es jetzt richtig verstanden habe, dann kannst du aber auch gleich

    template <typename T1, typename T2>
    typename std::common_type<T1, T2>::type max(T1 t1, T2 t2)
    {
        return t1 > t2 ? t1 : t2;
    }
    

    schreiben, oder?



  • Sone schrieb:

    std::common_type<T1, T2>::type

    Ja.
    Sofern common_type das korrekte macht. Ich denke ja, habe es aber noch nie verwendet.
    Das coole and decltype ist, dass es direkt den Code widerspiegelt. So ist zB
    declytpe(char(1)*char(1)) == int
    während common_type<char, char>::type == char wäre.

    In diesem Fall wäre common_type OK, aber das sollte man dennoch im Hinterkopf behalten.


  • Mod

    Shade Of Mine schrieb:

    Sofern common_type das korrekte macht. Ich denke ja, habe es aber noch nie verwendet.

    common_type (sofern nicht durch den Nutzer spezialisiert) ist über decltype(true?declval<T>():declval<U>()) definiert (20.9.7.6/3)

    Eine etwas bessere Variante dürfte

    template <typename T1, typename T2>
    typename std::common_type<T1, T2>::type max(T1&& t1, T2&& t2)
    {
        return t1 < t2 ? std::forward<T2>( t2 ): std::forward<T1>( t1 );
    }
    

    sein. Damit wird auch mit kompatiblen lvalues sinnvoll umgegangen (und bei Gleichheit hat der linke Parameter Vorrang, was bei Verkettung das Naheliegendere sein dürfte).


Anmelden zum Antworten