Template-Rekursion vs. #define. Ich packs net!



  • template<> //leeres template für template spezialisierung
    void TEST<1>(const char*& buf, unsigned long& u1, unsigned long& u2, unsigned i) 
    { 
        u1 += buf[i]; 
        u2 += u1; 
    }
    

    so muss das aussehen



  • template<unsigned n>
    void TEST(const char*& buf, unsigned long& u1, unsigned long& u2, unsigned i = 0)
    {
    	TEST<n / 2>(buf, u1, u2, i);
    	TEST<n / 2>(buf, u1, u2, i + (n / 2));
    }
    // Muss da nicht noch ein template<> hin?
    template<>
    void TEST<1>(const char*& buf, unsigned long& u1, unsigned long& u2, unsigned i)
    {
    	u1 += buf[i];
    	u2 += s1;
    }
    

    Wenn du es nicht rekursiv haben willst, warum machst du dann keine for-Schleife ohne templates draus?

    edit:
    Hauptsache 3mal dasselbe gepostet. 😮



  • Jippieh, danke 👍 . War ja echt saublöd von mir. Eine Frage habe ich noch an euch. Welche Variante findet ihr besser bzw. performanter? Es kommt an dieser Stelle nämlich ziemlich auf die Performance an.

    Thx,

    Rudi 🙂



  • Ich meine natürlich: Die 4 Parameter die ständig übergeben werden... optimiert das der Compiler weg, dass es also gleichbedeutend mit der hässlichen Template-Lösung ist...?



  • @cd: Ich möchte das zur Compilezeit stehen haben, so als ob ich den Code 100 mal abgetippt habe um die performance zu verbessern. Also ähnlich wie die Lösung mit den defines.



  • korrektur: Ich meinte vor 2 Posts natürlich die hässliche #define-Lösung 🙄



  • Ich denke die Lösung mit den 5 Defines wird schneller sein als das Template. Dass der Compiler in beiden Fällen den selben Code erzeugt ist IMHO nicht denkbar. Er wird ein gleiches Ergebnis bringen aber dennoch langsamer sein. Oder täusche ich mich? 😕



  • nicht fragen, asm listings lesen.



  • PeterTheMaster schrieb:

    nicht fragen, asm listings lesen.

    Die bestätigen meine Vermutung. Ich wollte nur wissen ob es bei wem anders auch der Fall ist oder ob da die Templates vom Compiler geinlined werden können wenn man sie nur einmal im Code benutzt. Ansonsten könnte man ja auch die Schleife benutzen wenn man defines vermeiden will. Die wär dann ja noch schneller als die Templaterekursion 😉 .



  • Nur allegemein.
    Also ich glaube nicht, dass man bei der heutigen Leistung der PC's einen Geschwindigkeitsunterschied zwischen den o.g. defines oder Templates feststellen kann.
    Ich würde immer Templates den Vorzug geben weil u.a. wie Du ja selbst gemerkt hast, der Compiler sofort meckert wenn was nicht ganz korrekt ist.
    #defines sollte man eigentlich nur noch in Ausnahmefälle verwenden.
    Was übrigens den Inline Code angeht ist noch lange nicht gesagt, das da wo inline draufsteht inline drin ist. Will sagen, dass der Compiler das oftmals einfach ignoriert. Desweiteren hat ein inline code den Nachteil, dass Du keinen Breakpoint setzen kannst.

    Gruß
    Gerhard



  • @Gerhard: Was du sagst ist mir völlig klar. Es steht aber nicht explizit inline da. Der Compiler kann aber nach eigenem Ermessen Sachen inlinen. Die Funktion oben sieht aus wie ein Teil einer Checksummenberechnung (oder so ähnlich). Wenn du eine Checksumme für eine 2 GB Datei berechnest macht es sehr wohl einen Unterschied ob noch etliche Funktionsaufrufe drin sind oder nur der Code was größer ist und du dafür kürzere Rechenzeiten hast. In dem Fall müsste 2.147.483.648 Mal die Funktion TEST<1> mit 4 Parametern aufgerufen werden (von TEST<...> mal ganz zu schweigen. Sagen wir mal ein Funktionsaufruf dauert 0,1 ms (ich weiß es nicht genau). dann würden ca. dreieinhalb Minuten Sekunden nur an Funktionsaufrufen für TEST<1> verloren gehen. Von daher wäre es nicht schlecht wenn das ganze geinlined würde.



  • Ja, ja ich will auch um Gottes Willen keine Diskussion über Compileroptimierung anfangen. Habe selber mal vor langen Jahren mit ASM8086 angefangen und da wurden noch Erbsen gezählt (welche Daten lade ich in ein Register, wieviel Zyklen braucht der Professor um ein Word aus dem Ram zu laden usw.)
    Bei den heutigen modernen Compilern (zumindest gilt das für den BCB6) fällt es mir manchmal schwer zu glauben, ob er das wirklich so optimiert wie ich es vorgebe oder ob er nicht (weil er es in der Regel auch beser weiß) eben ganz anders. Bsp. Auswahl 80386,80486,Pentium,Pentium Pro usw.
    Ansonsten gebe ich Dir völlig recht, dass man bei großene Datenmengen einiges herauskitzeln kann. Bsp. Wann immer es geht ist eine for Schleifer schneller als eine do/while Schleife.

    Gruß
    Gerhard



  • Hallo,
    also ich habe den Code mal ein kleines bischen umgebaut (spezialisierte struct + inline-static-Memberfunktion) mit dem Ergebnis, dass mein VC 6 *exakt* den selben Code für beide Varianten (Template und define) generiert.



  • @Hume: Hast du den Code noch? Würde mich auch interessieren wie man so ein "loop-unrolling" mit Templates realisieren kann. Hast du die struct innerhalb einer Funktion definiert und dort dann die Unroll-Funktionen als inline deklariert reingepackt?



  • Hast du den Code noch? Würde mich auch interessieren wie man so ein "loop-unrolling" mit Templates realisieren kann.

    Ich habe wie gesagt an dem Code nichts großartiges gemacht. Zweifle also daran, dass er dir irgendwelche neuen erkenntnisse bringt. So sieht er aus:

    template<unsigned n>
    struct Bla
    {
    	static void test(const char*& buf, unsigned long& u1, unsigned long& u2, unsigned i = 0) 
    	{ 
    		Bla<n / 2>::test(buf, u1, u2, i); 
    		Bla<n / 2>::test(buf, u1, u2, i + (n / 2)); 
    	} 
    };
    
    template<>
    struct Bla<1>
    {
    	static void test(const char*& buf, unsigned long& u1, unsigned long& u2, unsigned i = 0) 
    	{ 
    		u1 += buf[i]; 
    		u2 += s1; 
    	} 
    };
    

    Also wie gesagt. Nur die Funktionen in eine struct reingezogen, da der VC damit besser umgehen kann.

    Aufgerufen habe ich dann:

    void func()
    {
    	__asm { int 3 }
    	TEST16(buffer);
    }
    void gunc()
    {
    	__asm { int 3 }
    	Bla<16>::test(buffer, s1, s2);
    }
    
    int main()
    {
        func();
        gunc();
    }
    


  • So hatte ich mir das schon in etwa gedacht. Trotzdem danke! 🙂
    EDIT: Warum rufst du Interrupt 3 in func und gunc auf? 😕



  • MaSTaH schrieb:

    EDIT: Warum rufst du Interrupt 3 in func und gunc auf? 😕

    das wirft einen in den debugger, genau in der zeile, wo es passiert.



  • das wirft einen sauber in den debugger.

    ...und man erspart sich das mühselige wühlen im Assemblercode auf der Suche nach der richtigen Funktion 😃



  • Achso, thx 😉 .


Anmelden zum Antworten