Anhang E. Promotion Trait

Die Idee eines Promotion Trait ist recht einfach: Bestimme den Rückgabetyp des Funktions-Templates abhängig von seinen Eingabeargumenten dadurch, dass für jede Typkombination ein Rückgabetyp hinterlegt ist.

Generische add-Funktion

An einer generischen Funktion add, die zwei Werte addiert, lässt sich diese Technik einfach darstellen. Das Funktions-Template besitzt die folgende Definition.

??? add(T1 first, T2 second){
    return first + second;
}

Um generisch zu sein, muss der Rückgabetyp von den Argumenten abhängen. Das lässt sich aber nicht allgemein bestimmen, da für zwei Argumente vom Typ double und int der Rückgabetyp double, hingegen für zwei Typen long long und int der Rückgabetyp long long sein sollte. In Listing E.1 wird der Rückgabetyp aus dem Funktions-Template extrahiert und über ein typdef zur Verfügung gestellt. Virtualität zur Compile-Zeit sorgt dafür, dass jedes Funktions-Template zur Laufzeit seinen richtigen Rückgabetyp besitzt.

promotionTrait.cpp

01 #include <iostream>
02
03 template<typename T1, typename T2>
04 struct PromotionTrait{
05 };
06
07 template<typename T>
08 struct PromotionTrait<T,T>{
09   typedef  T ResultT;
10 };
11
12 template<>
13 struct PromotionTrait<int,long long int>{
14   typedef long long int ResultT;
15 };
16
17 template<>
18 struct PromotionTrait<long long int,int>{
19   typedef long long int ResultT;
20 };
21
22 template<>
23 struct PromotionTrait<int,double>{
24   typedef double ResultT;
25 };
26
27 template<>
28 struct PromotionTrait<double,int>{
29   typedef double ResultT;
30 };
31
32 template<typename T1, typename T2>
33 inline typename PromotionTrait<T1,T2>::ResultT add(
     T1 first, T2 second){
34     return first + second;
35 }
36
37 int main(){
38
39   std::cout << std::endl;
40
41   std::cout << "add(1,1)= " << add(1,1) << std::endl;
42   std::cout << "add(1,2.1)= " << add(1,2.1)  << std::endl;
43   std::cout << "add(1000LL,5)= " << add(1000LL,5)
               << std::endl;
44
45   std::cout << std::endl;
46
47 }
Listing E.1 Promotion Trait für eine generische Addierfunktion

Betrachten wir zuerst das Promotion Trait PromotionTrait in Zeile 3. Es ist nicht vollständig implementiert, da ihm der typedef für den Rückgabetyp fehlt. Dieses primäre Template, das keine Einschränkung bezüglich seiner Argumente besitzt, schreibt die C++-Syntax vor. Es folgen die Spezialisierungen des Templates. Die Spezialisierung in Zeile 7 wird verwendet, wenn die zwei Argumente vom gleichen Typ sind. Ist das der Fall, wird genau der Typ der Eingabeargumente als Rückgabetyp über typedef T ResultT zurückgegeben. Alle anderen vollständigen Spezialisierungen werden genau dann verwendet, wenn jeweils die Argumenttypen den Parametertypen entsprechen. So wird durch add(1,2.1) (Zeile 42) das Template struct PromotionTrait<int,double> (Zeile 22) angewandt. Dieses Template gibt über den Aufruf typename PromotionTrait<T1,T2>::ResultT den Typ double zurück.

Die Ausgabe zeigt das beschriebene Verhalten.

Promotion Trait zur Addition von Werten

Für jeden potenziellen Datentyp eine Spezialisierung von PromotionTrait vorzuhalten, hat zwei entscheidende Nachteile:

  1. Die Kombinationsmöglichkeiten steigen in der Größenordnung n*n, wenn n die Anzahl der Datentypen ist.

  2. Für jeden neuen Datentyp müssen alle Spezialisierungen zweimal implementiert werden.

Das geht deutlich einfacher mit decltype (siehe Kernsprache).