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.
-
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 hierint(-10) >> 1
als Ergebnis -5 rauskommt.
-
danke, dass mit den type-traits funktioniert klasse
-
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.
-
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.