Template-Methode mit Default-Parameter



  • scary...

    @drakon: Hast du den Fehler reported?



  • Hallo,

    vielen Dank für die vielen Rückmeldungen. Ich hab jetzt hier
    den Fehler gemeldet.

    djohn



  • hustbaer schrieb:

    scary...

    @drakon: Hast du den Fehler reported?

    Nein. Bin gester nicht dazu gekommen. Wollte eigentlich einen exakten Beschreib (auch für meinen Blog) von dem Fehler machen.

    Ich habe mich gestern dort extra noch angemeldet. 😛

    @djohn:
    Da ich ja bereits den Fehler analysiert habe wäre es vielleicht gut das auch noch zu melden. Dann können die sich ein wenig Arbeit sparen.. ^^
    Ich werde mal in einem Kommentar den Fehlerbeschreib ergänzen.



  • Habe gerade noch ein paar Sachen ausprobiert. Mit freien template Funktionen funktioniert es und auch wenn man die Definition inline macht (was denke ich der Hauptgrund ist, dass den Fehler noch niemand bemerkt hat).



  • Der Bug tritt mit freien Funktionen genau so auf:

    template<typename NumericType> 
    void foobar(NumericType value, NumericType step = NumericType());
    
    template<typename NumericType> 
    void foobar(NumericType value, NumericType step)
    {
        NumericType dummy = step;
    	std::cout << value << ", " << step << std::endl;
    }
    
    int main() 
    { 
    	foobar(2);
    	foobar(3.14);
    	return 0;
    }
    
    // output:
    // 2, 0
    // 4.27698e+086, 1.16762e-307
    

    Scheint aber wirklich davon abhängig zu sein dass Deklaration und Definition getrennt sind. Und ich kann's auch nicht mit etwas anderem als double reproduzieren. Und das auch nur, wenn vorher oder nachher ein Aufruf mit etwas anderem als double erfolgt.

    Auch nicht uninteressant folgendes:

    template<typename NumericType> 
    void foobar(NumericType value, NumericType step = 2); // <- hier direkt 2 statt NumericType() (0 oder andere Integer gehen genau so)
    
    template<typename NumericType> 
    void foobar(NumericType value, NumericType step)
    {
        NumericType dummy = step;
    	std::cout << value << ", " << step << std::endl;
    }
    
    int main() 
    { 
    	foobar(2);
    	foobar(3.14);
    	return 0;
    }
    
    // output:
    // 2, 2
    // 4.27698e+086, 3.75217e-308
    

    Immer noch (fast) der selbe falsche Output.

    Wenn man als Default-Wert allerdings ein double Literal hinschreibt...

    template<typename NumericType> 
    void foobar(NumericType value, NumericType step = 2.71828); // <- jetzt mit double literal hier
    
    template<typename NumericType> 
    void foobar(NumericType value, NumericType step)
    {
        NumericType dummy = step;
    	std::cout << value << ", " << step << std::endl;
    }
    
    int main() 
    { 
    	foobar(2);
    	foobar(3.14);
    	return 0;
    }
    
    // output:
    // 2, 1949120276
    // 3.14, 2.71828
    

    Auch falsch, aber ganz anders falsch 🙂



  • Der 64 Bit Compiler scheint übrigens genau so betroffen zu sein.



  • hustbaer schrieb:

    Der Bug tritt mit freien Funktionen genau so auf:

    Ah. Ich habe das nur mit direkt definierten freien Funktionen probiert.

    Der 64 Bit Compiler scheint übrigens genau so betroffen zu sein

    f.bar(2);
    000000013F39165B  xorpd       xmm2,xmm2  
    000000013F39165F  mov         edx,2
    

    Uh, oh. Ja.. sieht so aus.. ^^
    Aber es gibt keinen Laufzeitfehler bei mir.

    Scheint wirklich hauptsächlich an der Trennung zu liegen. Zum Glück implementieren die meisten templates direkt. 😛



  • Tjaaah... die meisten.

    In einem grösseren Projekt das ich gerade entwickle (mit VC 2005) hab' ich *einige* Templates mit getrennter Deklaration und Definition. Zwecks übersichtlichkeit der Header Files (Definition steht in eigenen .inl Files).
    Und auch mit Default-Parametern und die Variablen sind auch oft vom Typ double 😞

    EDIT:
    Wobei... dort werden eigentlich nur doubles verwendet, und nie was anderes. Sollte dann OK sein. Hab auch noch keinen derartigen Fehler beobachtet. Doof ist es trotzdem. /EDIT



  • @hustbaer

    Beim Versuch ein Minimalbeispiel zu erstellen, konnte ich den Fehler bei freien Funktionen auch nicht reproduzieren. Hatte da wahrscheinlich wie drakon noch eine der anderen Bedingungen wegreduziert. Bei Deiner zweiten Variante (Default-Wert ist ein int) reicht es aus, nur eine Template-Instanz mit double zu erzeugen um zumindest bei VS2005 den Fehler zu provozieren. Die zusätzliche Bedingung, dass man mindestens 2 Template-Instanzen mit unterschiedlichen Typen für den Fehler braucht, fällt dann weg.

    Ich hatte auch nur wegen der Übersichtlichkeit Deklaration und Definition getrennt, kein großes Problem, dass jetzt zu ändern. Aber wenn so ein Fehler erstmal auftritt, ist man natürlich unsicher, unter welchen Bedingungnen noch dieses undefinierte Verhalten auftreten kann.
    Deshalb, nochmal Danke an alle die sich an der Diskussion beteiligt haben, ich denke, wir haben jetzt ganz gut eingegrenzt, wann der Fehler auftritt.

    djohn



  • Noch was lustiges...
    Folgendes compiliert mit VS 2010:

    #include <iostream>
    
    int g_i = 42;
    
    template<typename T> 
    void baz(T a1, T* a2 = &g_i); // <- default argument should only work for T = int
    
    template<typename T> 
    void baz(T a1, T* a2)
    {
    	std::cout << a1 << ", " << *a2 << std::endl;
    }
    
    class c {};
    
    std::ostream& operator << (std::ostream& os, c const&)
    {
    	return os;
    }
    
    int main() 
    {
    	baz(2);
    	baz(3.14);   // compiles OK, but should not
    	baz("test"); // compiles OK, but should not
    	baz(c());    // compiles OK, but should not
    	return 0;
    }
    

    Beim Ausführen kommt natürlich nur Mist raus...

    😮 😮 😮


Anmelden zum Antworten