template-funktion je nach variablen-typ



  • hi,

    wie kann man folgendes in einer template-funktion realisieren? ich möchte gern, dass je nach typ der übergebenen variablen eine anderer berechnung innerhalb der funktion geschieht. ich möchte gern vermeiden für jeden typ eine eigene funktion schreiben zu müssen.

    template <class T> T Average(T a, T b)
    {
      // int-mittelwert
      if (T == int)
        return ((a + b) >> 1);
    
      // nachkommastellen erhalten bei double
      if (T == double)
        return ((a + b) / 2.0);
    }
    


  • Hallo,

    statt if-Abfragen, kannst du die Funktion auch spezialisieren:

    template <typename T> 
    T Average(T a, T b);
    
    template<>
    int Average(int a, int b) {
    }
    
    template<>
    double Average(double a, double b) {
    }
    

    mfg
    v R



  • naja das wollte ich ja vermeiden, für jeden typ (char, short, int, long, double, float usw.) ne funktion schreiben zu müssen.

    ich möchte, dass wenn der typ ein ganzzahltyp ist, die variante 1 aufgerufen wird, und wenn der typ ein gleitkommatyp ist, dass variante 2 verwendet wird.



  • mach einfach return (a+b)/2;

    Dein Compiler sollte schlau genug sein, dass er bei Ganzzahltypen aus der Division eine Schiebeoperation macht.


  • Mod

    MFK schrieb:

    mach einfach return (a+b)/2;

    Dein Compiler sollte schlau genug sein, dass er bei Ganzzahltypen aus der Division eine Schiebeoperation macht.

    das bezweifle ich. ein mittelweg wäre, das template nur für gleitkommatypen zu spezialisieren, es gibt ja viel mehr integrable typen als solche. (oder könnte man evtl. einen >> operator für float/double etc. definieren? 🙂 )



  • camper schrieb:

    MFK schrieb:

    mach einfach return (a+b)/2;

    Dein Compiler sollte schlau genug sein, dass er bei Ganzzahltypen aus der Division eine Schiebeoperation macht.

    das bezweifle ich.

    Das hängt stark vom Compiler ab.
    Der VC 6.0 macht daraus z.B.:

    mov         eax,dword ptr [ebp-8]
    mov         ecx,dword ptr [ebp-4]
    add         eax,ecx
    cdq
    sub         eax,edx
    sar         eax,1
    

    Intels 5.0 hingegen:

    mov         eax,dword ptr [ebp-8]
    add         eax,dword ptr [ebp-4]
    add         eax,80000000h
    adc         eax,80000000h
    sar         eax,1
    

    (Falls die Operanden zur Compilezeit bekannt sind, rechnen beide Compiler das Ergebnis bereits zur Compilezeit aus).

    Statt einfach nur zu zweifeln würde ich lieber nachschauen.

    h möchte gern, dass je nach typ der übergebenen variablen eine anderer berechnung innerhalb der funktion geschieht

    Da helfen Type-Traits. Z.B. die von boost:

    template <bool> struct Select {};
    template <class T>
    T avg_impl(T a, T b, Select<false>)
    {
        return (a + b) / 2;
    }
    
    template <class T>
    T avg_impl(T a, T b, Select<true>)
    {
        return (a + b) >> 1;
    }
    
    template <class T>
    inline T avg(T a, T b)
    {
        return avg_impl(a, b, Select<boost::is_integral<T>::value>());
    }
    

    Verwendest du zusätzlich boost::enable_if, kannst du dir die forwarding-Funktion sparen.

    template <class T>
    typename boost::enable_if<boost::is_integral<T>::value, T>::type avg(T a, T b)
    {
        return (a + b) >> 2;
    }
    
    template <class T>
    typename boost::disable_if<boost::is_integral<T>::value, T>::type avg(T a, T b)
    {
        return (a + b) / 2;
    }
    


  • camper schrieb:

    MFK schrieb:

    mach einfach return (a+b)/2;

    Dein Compiler sollte schlau genug sein, dass er bei Ganzzahltypen aus der Division eine Schiebeoperation macht.

    das bezweifle ich.

    Ich aber nicht. Einen Compiler, der hier nicht optimiert, kannst du getrost entsorgen.
    Ausserdem schreibt der Standard nicht vor, dass hier

    int(-10) >> 1
    

    als Ergebnis -5 rauskommt.



  • danke, dass mit den type-traits funktioniert klasse


  • Mod

    schön schön 🙂 deshalb sagte ich ja auch bezweifeln und nicht einfach nein.
    im übrigen ein gutes beispiel, warum man - wenn möglich und sinnvoll - vorzeichenlos rechnen sollte.



  • camper schrieb:

    im übrigen ein gutes beispiel, warum man - wenn möglich und sinnvoll - vorzeichenlos rechnen sollte.

    Das sehe ich aber nur für das Arbeiten auf Bitebene so. Ansonsten sollte man so rechnen, wie es der Situation angemessen ist. Und wenn ich da durch 2 dividiere, dann schreibe ich auch / 2.


  • Mod

    groovemaster schrieb:

    camper schrieb:

    im übrigen ein gutes beispiel, warum man - wenn möglich und sinnvoll - vorzeichenlos rechnen sollte.

    Das sehe ich aber nur für das Arbeiten auf Bitebene so. Ansonsten sollte man so rechnen, wie es der Situation angemessen ist. Und wenn ich da durch 2 dividiere, dann schreibe ich auch / 2.

    das meinte ich nicht - aber wie man am assembler listing sehen kann, ist die benutzung von shift als ersatz für / 2 nicht trivial, wenn die zahlen vorzeichenbehaftet sind. insofern kostet es rechenkapazität. ich schrieb auch ausdrücklich möglich und sinnvoll, also in (fast) allen fällen in denen negative zahlen nicht auftreten können oder sinnlos sind.


Anmelden zum Antworten