Templates oder Schablonen sind "Programmgerüste", die eine vom Datentyp unabhängige Programmierung ermöglichen. Templates unterstützen die generische Programmierung.
In C++ sind Schablonen von großem Nutzen, insbesondere wenn sie mit Vererbung und Überladen von Operatoren kombiniert werden. Die C++-Standardbibliothek stellt viele nützliche Komponenten in Form eines Template-Rahmenwerkes, zur Verfügung.
Auch die bei Hewlett-Packard (HP) entwickelte STL (englisch standard template library), aus der vieles in die C++-Standardbibliothek übernommen wurde, besteht, wie der Name vermuten lässt, im Wesentlichen aus Templates.
Technischer Überblick
Es gibt zwei Arten von Templates in C++: Funktionstemplates und Klassentemplates.
Funktionstemplates
Ein Funktionstemplate verhält sich wie eine Funktion, die in der Lage ist, Argumente verschiedener Typen entgegenzunehmen. Die C++-Standardbibliothek enthält beispielsweise das Funktionstemplate
max(x, y)
Es gibt entweder x oder y zurück, und zwar abhängig davon, welches der beiden Argumente größer ist. Das Funktionstemplate max() könnte etwa folgendermaßen definiert sein:
template <typename T> T max(T x, T y) { if (x < y) return y; else return x; }
Diese Schablone kann genauso aufgerufen werden wie eine Funktion:
cout << max(3, 7); // gibt 7 aus
Anhand der Argumente macht der Compiler fest, dass es sich um einen Aufruf an max(int, int) handelt und erzeugt eine Variante der Funktion, bei der der Typ T zu int festgelegt wird.
Der Schablonenparameter könnte auch explizit angegeben werden. Das sähe dann so aus:
cout << max<int>(3, 7); // gibt ebenfalls 7 aus
Das Ganze funktioniert sowohl für int also auch für string oder irgendeinen anderen Typ, für den der Vergleich x < y eine wohldefinierte Operation darstellt. Bei selbstdefinierten Typen macht man von Operator-Überladung Gebrauch, um die Bedeutung von < für den Typ festzulegen und dadurch die Verwendung von max() für den betreffenden Typ zu ermöglichen.
Das Beispiel für sich genommen mag nicht besonders nützlich erscheinen, im Zusammenspiel mit der C++-Standardbibliothek erschließt sich aber eine enorme Funktionalität für einen neuen Typ ganz einfach dadurch, dass man ein paar Operatoren definiert. Allein schon durch die Definition von < wird ein Typ in die Lage versetzt, mit den Standardalgorithmen sort(), stable_sort(), und binary_search() zusammenzuarbeiten, sowie mit Datenstrukturen wie Mengen, Stapeln, assoziativen Feldern, usw.
Klassentemplates
Ein Klassentemplate wendet das gleiche Prinzip auf Klassen an. Klassentemplates werden oft zur Erstellung von generischen Containern verwendet. Beispielsweise verfügt die C++-Standardbibliothek über einen Container, der eine verkettete Liste implementiert. Um eine verkettete Liste von int zu erstellen, schreibt man einfach list<int>. Eine verkettete Liste von strings wird zu list<string>. Mit list ist ein Satz von Standardfunktionen definiert, die immer verfügbar sind, egal was man als Argumenttyp in den spitzen Klammern angibt.
==== [[Bild:
==
==
Spezialisierungen == == ==]] ==
Klassentemplates lassen sich spezialisieren, d.h. man kann Klassen für bestimmte Datentypen als Template-Argumente gesondert implementieren. Davon machen auch manche Implementierungen der C++-Standardbibliothek (beispielsweise die der GCC) Gebrauch. Die Klasse vector ist für den Elementtyp bool als Bitmap implementiert. Auch entnimmt die basic_string-Klasse die Informationen zum Umgang mit den einzelnen Zeichen der Struktur char_traits, die für den Datentyp char und beispielsweise auch wchar_t spezialisiert ist.
Die Deklaration von Spezialisierungen ähnelt der von normalen Templates, allerdings sind die dem Schlüsselwort template folgenden spitzen Klammern leer, und dem Funktions- bzw. Klassennamen folgen die Templateparameter.
Beispiel:
template<> class vector<bool> { // Implementierung von vector als Bitmap };
Teilweise Spezialisierungen
Des Weiteren gibt es auch die sogenannte teilweise Spezialisierung, die die Behandlung von Spezialfällen innerhalb eines Templates ermöglicht.
Beispiel:
template<int zeilen, int spalten> class Matrix { // Implementierung einer Matrix-Klasse };
template<int zeilen, 1> class Matrix { // Implementierung einer 1-spaltigen Matrix-Klasse, d.h. einer Vektor-Klasse };
Wichtig zu erwähnen ist, dass beide Klassen komplett voneinander unabhängig sind, d.h. sie erben weder Konstruktoren oder Destruktoren noch Elementfunktionen bzw. Datenelemente voneinander.