Templates (deutsch: Schablonen) sind ein mächtiges Instrument zur effektiven Kodierung von Algorithmen in C++. Insbesondere die Wiederverwendbarkeit des Kodes wird drastisch verbessert.
Oftmals zeigt es sich, dass die Programmierung bestimmter Algorithmen völlig unabhängig davon ist, welchen konkreten Typ die zu bearbeitenden Daten haben. Denken wir zum Beispiel an einen Algorithmus, der zwei Werte miteinander vertauschen soll. In C lässt sich dies zunächst relativ schnell hinschreiben; die zwei zu vertauschenden Werte sollen dazu in den Variablen left und right stehen:
temp = left; left = right; right = temp;
Dieser Algorithmus wird so oft gebraucht, dass er in eine Funktion swap zur Verfügung gegossen werden soll. Und da fangen unsere Probleme an!
C ist eine streng typisierte Sprache - für jede Variable und jeden Funktionsparameter muss zwingend ein Typ angegeben werden. Welchen Datentyp sollen nun also die Variablen left, right, temp bekommen? Um das ganze möglichst universell zu halten, könnte man versucht sein, für jeden bekannten Datentyp wie int, double oder float eine eigene Funktion zu schreiben. Eine langweilige und fehlerträchtige Arbeit! Und dabei hat man die benutzerdefinierten Datentypen noch nicht berücksichtigt.
Einen Ausweg aus dieser Situation kann man nur finden, wenn es gelingt, den Algorithmus des Vertauschens zweier Werte (oder zweier »Objekte«) völlig vom Typ der zu vertauschenden Objekte zu trennen. Dazu hat C++ den Mechanismus der Templates. Damit lässt sich ein Algorithmus zum Vertauschen zweier Objekte folgendermaßen als Templatedefinition aufschreiben:
template<class T> void swap( T &left, T &right) { T temp; temp = left; left = right; right = temp; }
An den Stellen, an denen normalerweise eine Typangabe steht, wie bei der Angabe des Funktionsparamtertyps oder der Deklaration der Variablen temp, ist hier der Templateparameter T getreten. Erst bei der Verwendung des Templates (der Templateinstanzierung) wird T durch einen konkreten Typ ersetzt:
int a, b; double x, y; StockItem item1, item2; swap( a, b); // ersetzt T durch int swap( x, y); // ersetzt T durch double swap( item1, item2); // ersetzt T durch StockItem
Der Programmierer musste nur ein einziges Mal das Templates (den Algorithmus) zum Vertauschen zweier Werte aufschreiben - der Compiler generiert »automatisch« für jeden beliebigen Datentyp eine swap() Funktion. Was für eine Arbeitserleichterung! Wichtig ist, dass der Compiler (und nicht erst der Linker!) beim Auftreten einer Templateinstanzierung die Templatedefinition sehen kann. Das heisst, Templatedefinitionen gehören in Headerdateien!
Beim vorliegenden Beispiel handelt es sich um ein Funktionstemplate. Datenunabhängige Algorithmen lassen sich jedoch auch für ganze Klassendefinitionen formulieren. Dann spricht man von einem Klassentemplate. Wichtigstes Anwendungsgebiet hierfür sind die Containerklassen, wie Arrays, Listen, Stacks und Queues. Diese müssen ja nur Objekte möglichst effizient speichern - welchen Typ die verwalteten Objekte haben, ist dem Container letztlich egal. In der nächsten Artikelfolge werden wir daher ein Klassentemplate kennenlernen, welches Daten in einem Stack speichert.