====== Template Funktionen ====== Ein Funktionstemplate erlaubt es eine Funktionalität für verschiedene Typen bereitzustellen. Man könnte auch sagen, das eine Template Funktion eine Familie von Funktionen darstellt. ===== Definition einer Template Funktion ===== Wie im Kapitel [[cpp:template:start|Was sind Templates]] bereits erwähnt definiert man Templates wie folgt: // Pseudocode template {function definition} In diesem Kapitel wird genauer darauf eingegangen was passiert wen der Compiler auf ein Template trifft. Das folgende Beispiel, welches das Minimum zweier Variablen ermittelt, dient uns als Veranschaulichung für die Erklärungen in diesem Kapitel. ==== Beispiel ==== // File minimum.hpp template inline Type const& minimum(Type const& a, Type const& b) { return a < b ? a : b; } ===== Nutzung von Template Funktionen ===== Das folgende Beispielprogramm zeigt, wie man die Funktion minimum() verwendet #include "minimum.hpp" #include #include int main(void) { std::cout << "minimum(\"aa\", \"ab\"): " << minimum(std::string("aa"), std::string("ab")) << std::endl; std::cout << "minimum(9, 7): " << minimum(9, 7) << std::endl; return 0; } Die Ausgabe ist wie erwartet:
''minimum("aa", "ab"): aa''
''minimum(9, 7): 7''
==== Instantiierung eines Templates ==== Sobald der Compiler auf einen Aufruf der Templatefunktion stößt, wird das Template für den aufgerufen Typ //instantiiert (im Sinne vom Erzeugen der richtigen Funktion)//. Das heißt, dass der Compiler für den Aufruf minimum(std::string("aa"), std::string("ab")); eine Funktion inline std::string const& test(std::string const& a, std::string const& b) { // Inhalt wie oben im Template } generiert. Das selbe passiert beim Aufruf für die Funktion mit den Integer werten. ===== Bestimmung der Argumente ===== Wenn wir //minimum()// aufrufen, bestimmt der Compiler anhand der Argumente die wir an //minimum()// übergeben wie der Templateparameter auszusehen hat. Übergeben wir also zwei Integer an //minimum()// ersezt der Compiler den Template Parameter **Type** mit **int**. Allerdings ist zu beachten, dass bei dieser Art der Argumentbestimmung keine automatische Typkonvertierung erlaubt ist. Das heißt dass der folgende Code nicht erlaubt ist. // ... std::cout << "minimum(7, 4.2): " << minimum(7, 4.2) << std::endl; //Fehler: 7 und 4.2 sind nicht vom gleichen Typ // ... Um dieses Problem zu umgehen gibt es folgende Möglichkeiten: * Man castet beide Argumente so dass sie vom gleichen Typ sind.
... minimum(static_cast(7), 4.2) ... * Man qualifiziert den Aufruf durch direkte Angabe des Template Parameters ... minimum(7, 4.2) ... * Man ändert die Template Parameter Liste damit verschiedene Typen erlaubt sind ===== Template Parameter ===== Funktionstemplates haben zwei Arten von Parametern - Die Templateparameter - Die Funktionsparameter Um zwei Typen für unsere Funktion //minimum()// zuzulassen erweitern wir unsere Templatefunktion wie folgt: template inline Type1 minimum(Type1 const& a, Type2 const& b) { return a < b ? a : b; } Es fällt auf das bei dieser Funktion der Rückgabewert von einer [[cpp:ref:start|Referenz]] auf einen Wert geändert wurde. Das kommt daher, weil bei der Konvertierung zwischen Type1 und Type2 ein temporäres Objekt erzeugt wird. Die Rückgabe von Temporären Objekten als Referenz führt zu undefiniertem Verhalten was inakzeptabel ist. Außerdem bestimmt der erste Parameter auch den Rückgabewert der Funktion was für den Aufrufer der Funktion unerwartet sein kann, wenn etwa bei einem Integer - Double Vergleich trotz des kleineren Double Wertes der Double Wert als Integer Wert zurückkommt, wie in folgendem Beispiel. ... minimum(6, 3.2) ... // liefert 3 als Ergebnis
Daher ist es nötig das Funktionstemplate erneut anzupassen. Es erhält als weiteren Template Parameter den Typ des Rückgabewertes. template inline ReturnType minimum(Type1 const& a, Type2 const& b) { return a < b ? a : b; } Der Typ des Rückgabewertes wird an den Anfang der Template Parameter Liste geschrieben, weil er nicht automatisch ermittelt werden kann da er nicht in der Parameterliste vorkommt. Die beiden anderen Parameter können wie gewohnt vom Compiler anhand der Funktionsparameter ermittelt werden. Der Aufruf gestaltet sich daher wie folgt: ... minimum(6, 4.2) ... // mimimum liefert einen double zurück (4.2) ===== Überladen von Template Funktionen ===== Auch das Überladen von Template Funktionen ist möglich. Das ist sinnvoll, wenn man für bestimmte Typen eine gesonderte Behandlung benötigt. Bei [[c:pointer|Zeigern]] will man normalerweise nicht die Adressen sondern die Werte hinter den Adressen vergleichen. Daher erweitert man die Minimum Funktion um eine Überladung. // Für alle normalen Typen template inline Type const& minimum(Type const& a, Type const& b) { return a < b ? a : b; } // Für Zeiger template inline Type const& minimum(Type* const& a, Type* const& b) { return *a < *b ? *a : *b; } Ruft man die Funktion mit Zeigern auf // ... int a = 72, b = 48; std::cout << "mimum(&a (points to 72), &b (points to 48)): " << minimum(&a, &b) << std::endl; // ... übersetzt der Compiler das Zeiger Template, da dessen Signatur am besten zum Aufruf passt. ===== Kapitel ===== Die folgenden Kapitel geben einen Einblick in die Programmierung mit Templates - [[cpp:template:start|Was sind Templates]] - **Template Funktionen** - [[cpp:template:class|Template Klassen]] - [[cpp:template:meta|Template Metaprogrammierung]] - [[cpp:template:danger|Gefahren bei der Programmierung mit Templates]] ===== Links ===== * [[http://forum.proggen.org/viewtopic.php?f=39&t=780|Diskussion im Forum]] * [[http://www.boost.org|Die Boost Bibliotheken]]