Schwierigkeiten mit templates



  • Eisenspitze schrieb:

    Für Zahlen funktioniert deine Methode natürlich, aber beim string hilft das wenig..oder verstehe ich daran irgendetwas nicht..? 😉

    Wunderbar funktioniert das für Strings. Probier es doch aus.



  • Natürlich hab ich das probiert bevor ich dir geschrieben hab - ich bin doch auf der Suche nach einer Lösung..!

    Leider klappt es eben nicht..!

    Das ist der Code:

    #include <string>
    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    void main()
    {
    	std::vector<string> strvec(5);
            for(size_t n(0);n < 5;++n)
            {
                    while(!(std::cin >> strvec[n]))
                    {
                            std::cout << "Error! Type in a number, please!\n";
                            std::cin.clear();
                            std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
                    }
            }
    
    		for(size_t n(0);n < 5;++n)
    		{cout << strvec[n] << "\n";}
    
    	system("Pause");
    }
    

    Also genau deiner nur eben für strings.

    Wenn ich:

    "Hallo Du"
    "ein Test"
    "und geht nicht"

    eingebe, kommt

    Hallo
    Du
    ein
    Test
    und

    heraus..!



  • Ahh. Natürlich. Jetzt verstehe ich dein Problem. Der operator>> liest nur bis zum ersten Whitespace...
    Vielleicht machst du eine Spezialisierung?

    Ach, btw: void main() ? Ist das dein ernst?



  • Okay, flags hab ich bisher nur ein paar mal so neben bei beim suchen gelesen, aber noch nie bewusst irgendwo wahrgenommen...

    Kannst du mir da auf die Sprünge helfen..? Hab grad im Netz gesucht und rumgespielt, aber ich bekomm´s nicht hin... 😞

    Meinst du ios::skipws..?

    Spezialisierung ist mir bekannt, nur wie muss ich´s mit ios::skipw schreiben..?

    Achso, das void main hab ich nur drin weil das im Skript so stand, wobei ich irgendwo im Hinterkopf hab dass es immer int main sein MUSS.
    -> stimmt das..?
    -> welche Hintergründe gibt´s da..?



  • Nun, mit Flags habe ich nichts gefunden, vielleicht jemand anders.

    Was du machen könntest ist eine Überladung mit einer Templatefunktion:

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


  • ja müsste inmain() heissen. warum? weil das der standard besagt als programmeinstiegspunkt

    du musst dir das so vorstellen, dein compiler bettet dein programm in eine laufzeitumgebung ein, die in etwa so aussieht:

    someFunction();
    // ...
    int returnValue = main();
    if ( returnValue == ... )
        ...
    somefunction();
    

    void main ist halt kein standardkonformes C++

    bei deinem letzten programm lässt du auch nur 5 worte eingeben durch die schleifen, daher nicht wundern wenn nur 5 wieder rauskommen



  • Cool, so klappt es..! 😃 😃

    Damit ich´s richtig verstehe:
    Damit haben wir jetzt eine überladene Template-Funktion und der Compiler sucht sich die richtige raus, je nach dem ob´s ein string Vektor ist, oder ein anderer..?

    @Skym0sh0
    Danke für die Erkärung..! 😃



  • 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


Anmelden zum Antworten