Übersicht über Vorlagen
Vorlagen, die auch als parametrisierte Typen bezeichnet werden, sind Mechanismen für das Generieren von Funktionen und Klassen auf der Basis von Typparametern. Indem Sie Vorlagen verwenden, können Sie eine einzelne Klasse oder Funktion entwerfen, die auf Daten zahlreicher Typen operiert, anstatt eine separate Klasse für die einzelnen Typen erstellen zu müssen.
Hinweise
Um beispielsweise eine typesafe-Funktion zu erstellen, die mindestens zwei Parameter zurückgibt, ohne Vorlagen zu verwenden, würden Sie wie folgt eine Reihe von überladenen Funktionen schreiben:
// what_are_templates1.cpp
// compile with: /c
// min for ints
int min( int a, int b ) {
return ( a < b ) ? a : b;
}
// min for longs
long min( long a, long b ) {
return ( a < b ) ? a : b;
}
// min for chars
char min( char a, char b ) {
return ( a < b ) ? a : b;
}
Mit Vorlagen können Sie diese Duplizierung auf eine einzige Funktionsvorlage reduzieren:
// what_are_templates2.cpp
// compile with: /c
template <class T> T min( T a, T b ) {
return ( a < b ) ? a : b;
}
Vorlagen können die Größe des Quellcodes erheblich reduzieren und die Codeflexibilität erhöhen, ohne die Typsicherheit zu senken.
Es gibt zwei Hauptarten von Vorlagen: Funktionsvorlagen und Klassenvorlagen. Im vorherigen Beispiel ist min eine Funktionsvorlage. Eine Klassenvorlage ist eine Klasse mit einem Parameter, z. B.:
// what_are_templates3.cpp
template <class T> class A {
T m_t;
public:
A(T t): m_t(t) {}
void f(T t);
};
int main() {
A<int> a(10);
}
Vorlagen werden mit Ausnahme einiger wichtiger Unterschiede in etwa wie andere Funktionen und Klassen deklariert und definiert. Eine Vorlagendeklaration definiert eine Funktion oder eine Klasse nicht vollständig. Sie definiert nur ein syntaktisches Skelett für eine Klasse oder Funktion. Eine tatsächliche Klasse oder Funktion wird mithilfe einer Vorlage durch eine sogenannte Instanziierung erstellt. Die einzelnen erstellten Klassen oder Funktionen werden als instanziiert bezeichnet. Eine Klassenvorlage beispielsweise:
template <class T> struct A { . . . };
kann verwendet werden, um Klassen für A<int>, A<char>, A<int*>, A<MyClass*> zu instanziieren usw.
Die Instanziierung von Klassen oder Funktionen kann explizit oder implizit durchgeführt werden. Die explizite Instanziierung ist eine Methode, mit der in Code angegeben wird, welche Versionen der Vorlage generiert werden sollen. Die implizite Instanziierung ermöglicht es, dass Vorlagen bei Bedarf an dem Punkt der ersten Verwendung instanziiert werden.
Vorlagen können auch durch einen Wertparameter parametrisiert werden. In diesem Fall wird der Vorlagenparameter wie der Parameter für eine Funktion deklariert. Gleitkommatypen und Klassentypen sind nicht als Wertparameter zulässig.
// what_are_templates4.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
template <int i> class A {
int array[i];
public:
A() { memset(array, 0, i*sizeof(int)); }
};
int main() {
A<10> a;
}
Ein häufiges Problem mit Vorlagen besteht darin, dass sie eine Einheitslösung sein können. Dies bedeutet, dass der gleiche Code für alle Typen gilt. Wenn Sie das Verhalten der Vorlage für einen bestimmten Typ anpassen müssen, können Sie die Spezialisierung verwenden. Mit der expliziten Spezialisierung kann eine Vorlage für einen bestimmten tatsächlichen Typ, nicht für einen generischen Typ, spezialisiert werden. Eine Klassenvorlage kann auch teilweise spezialisiert werden. Das ist hilfreich, wenn Sie über eine Vorlage mit mehreren Typparametern verfügen und Sie nur das Verhalten in Bezug auf einige, aber nicht alle Parameter anpassen möchten. Eine partielle Spezialisierung ist weiterhin generisch und erfordert echte Vorlagenargumente, um eine tatsächliche instanziierte Klasse zu erstellen.