Templates sind ein Werkzeug von C++, um parametrischen Polymorphismus zu unterstützen. Mithilfe von Templates können Benutzer ein allgemeines Muster für Klassen oder Funktionen deklarieren, sodass bestimmte Datenelemente in einer Klasse oder die Parameter und Rückgabewerte von Memberfunktionen beliebige Typen annehmen können.
Ein Template ist ein Werkzeug, das Typen parametrisiert;
Es gibt üblicherweise zwei Formen: Funktions-Templates und Klassen-Templates;
Funktions-Templates zielen auf Funktionen ab, die sich nur in den Parametertypen unterscheiden;
Klassen-Templates zielen auf Klassen ab, die sich nur in den Typen der Datenelemente und Memberfunktionen unterscheiden.
Der Zweck der Verwendung von Templates besteht darin, Programmierern zu ermöglichen, typunabhängigen Code zu schreiben. Wenn Sie beispielsweise eine swap-Funktion schreiben, die zwei int-Variablen vertauscht, kann diese Funktion nur int verarbeiten. Sie kann keine Typen wie double oder char verarbeiten. Um diese Typen zu vertauschen, müssten Sie eine weitere swap-Funktion schreiben. Der Zweck der Verwendung von Templates besteht darin, die Programmimplementierung typunabhängig zu machen. Beispielsweise kann eine swap-Template-Funktion sowohl int- als auch double-Vertauschungen verarbeiten. Templates können auf Funktionen und Klassen angewendet werden. Sie werden im Folgenden getrennt vorgestellt.
Hinweis:Die Deklaration oder Definition eines Templates kann nur im globalen Bereich, im Namespace-Bereich oder im Klassenbereich erfolgen. Das heißt, sie kann nicht im lokalen Bereich oder innerhalb einer Funktion erfolgen; zum Beispiel können Sie ein Template nicht in der main-Funktion deklarieren oder definieren.
I. Allgemeine Form von Funktions-Templates
1. Format eines Funktions-Templates:
template <class 形参名,class 形参名,......> 返回类型 函数名(参数列表)
{
函数体
}
Dabei sind template und class Schlüsselwörter. class kann durch das Schlüsselwort typename ersetzt werden. Hierbei gibt es keinen Unterschied zwischen typename und class. Die Parameter innerhalb von <> heißen Template-Parameter. Template-Parameter sind Funktionsparametern sehr ähnlich. Template-Parameter dürfen nicht leer sein. Sobald eine Template-Funktion deklariert ist, können Sie die Namen der Template-Parameter verwenden, um Membervariablen und Memberfunktionen in der Klasse zu deklarieren; das heißt, überall dort, wo in dieser Funktion eingebaute Typen verwendet werden können, können die Namen der Template-Parameter verwendet werden. Template-Parameter müssen durch die Template-Argumente initialisiert werden, die beim Aufruf der Template-Funktion angegeben werden. Sobald der Compiler den tatsächlichen Template-Argumenttyp bestimmt, sagt man, dass er eine Instanz des Funktions-Templates instanziiert hat. Zum Beispiel lautet die Template-Form der swap-Funktion:
template <class T> void swap(T& a, T& b){},
Wenn eine solche Template-Funktion aufgerufen wird, wird der Typ T durch den im Aufruf verwendeten Typ ersetzt, zum Beispielswap(a,b)wobeiaundbsindintTyp, und an diesem Punkt werden die Parameter in der Template-Funktion swapTdurchintersetzt, und die Template-Funktion wird zuswap(int &a, int &b). Und wennswap(c,d)wobeicunddJadoubleTyp, wird die Template-Funktion ersetzt durchswap(double &a, double &b), wodurch Code erreicht wird, dessen Funktionsimplementierung typunabhängig ist.
2. Hinweis: Für Funktions-Templates gibt es keinenh(int,int)solchen Aufruf,Der Typ der Template-Parameter kann nicht in den Argumenten eines Funktionsaufrufs angegeben werden. Aufrufe von Funktions-Templates solltenArgumentableitung verwendendurchgeführt werden, das heißt, nur h(2,3)solche Aufrufe können gemacht werden, oderint a, b; h(a,b)。
Beispieldemonstrationen von Funktions-Templates werden unten behandelt!
II. Allgemeine Form von Klassen-Templates
1. Das Format eines Klassen-Templates ist:
template<class 形参名,class 形参名,…> class 类名
{ ... };
Sowohl Klassen-Templates als auch Funktions-Templates beginnen mit template, gefolgt von einer Template-Parameterliste. Template-Parameter dürfen nicht leer sein. Sobald ein Klassen-Template deklariert ist, kann man die Namen der Parameter des Klassen-Templates verwenden, um Mitgliedsvariablen und Mitgliedsfunktionen in der Klasse zu deklarieren. Das heißt, überall dort, wo in der Klasse eingebaute Typen verwendet werden können, können Template-Parameternamen zur Deklaration verwendet werden. Zum Beispiel
template<class T> class A{public: T a; T b; T hy(T c, T &d);};
In Klasse A werden zwei Mitgliedsvariablen a und b vom Typ T deklariert, und außerdem wird eine Funktion hy mit Rückgabetyp T und zwei Parametern vom Typ T deklariert.
2. Erstellen eines Klassen-Template-Objekts: Zum Beispiel eine Template-KlasseA, dann ist die Methode zum Erstellen eines Objekts unter Verwendung des Klassen-TemplatesA<int> m;Nach der KlasseA, gefolgt von einer<>spitzen Klammer, und füllen Sie die entsprechenden Typen darin ein. Auf diese Weise wird die KlasseAüberall dort, wo Template-Parameter in der Klasse verwendet werden, werden durchintersetzt. Wenn ein Klassen-Template zwei Template-Parameter hat, ist die Methode zum Erstellen eines ObjektsA<int, double> m;Trennen Sie die Typen durch Kommas.
3. Bei Klassentemplates müssen die Typen der Template-Parameter explizit in den spitzen Klammern nach dem Klassennamen angegeben werden. Zum Beispiel ist es falsch,A<2> m;den Template-Parameter aufintzu setzen (Kompilierfehler: error C2079: 'a' uses undefined class 'A<int>'),Klassen-Template-Parameter haben nicht das Problem der Argumentableitung.Das heißt, ein ganzzahliger Wert kann nicht2alsintTyp abgeleitet und an den Template-Parameter übergeben werden. Um den Klassen-Template-Parameter aufintTyp, muss er so angegeben werdenA<int> m。
4. Die Methode zum Definieren von Memberfunktionen außerhalb eines Klassentemplates ist:
template<模板形参列表> 函数返回类型 类名<模板形参名>::函数名(参数列表){函数体},
Wenn beispielsweise eine Klasse A mit zwei Template-Parametern T1 und T2 eine void h()-Funktion enthält, lautet die Syntax zum Definieren dieser Funktion:
template<class T1,class T2> void A<T1,T2>::h(){}。
Hinweis:Beim Definieren von Klassen-Membern außerhalb der Klasse müssen die Template-Parameter nach template mit den Template-Parametern der zu definierenden Klasse übereinstimmen.
5. Nochmal zur Erinnerung: Die Deklaration oder Definition eines Templates kann nur im globalen, Namespace- oder Klassenbereich erfolgen. Das heißt, sie kann nicht im lokalen Bereich oder innerhalb einer Funktion erfolgen; zum Beispiel kann sie nicht in dermainFunktion deklariert oder definiert werden.
III. Template-Parameter
Es gibt drei Arten von Template-Parametern: Typparameter, Nicht-Typparameter und Template-Parameter.
1. Typparameter
1.1 Typ-Template-Parameter:Ein Typparameter besteht aus dem Schlüsselwort class oder typename, gefolgt von einem Spezifizierer, wie z. B.template<class T> void h(T a){}; wobeiTein Typparameter ist. Der Name des Typparameters wird vom Benutzer selbst festgelegt.Ein Template-Parameter repräsentiert einen unbekannten Typ.Ein Template-Typparameter kann überall im Template als Typspezifizierer verwendet werden, genau so wie eingebaute Typspezifizierer oder Klassentypspezifizierer; das heißt, er kann verwendet werden, um Rückgabetypen, Variablendeklarationen usw. anzugeben.
Originalversion des Autors:1.2, Man kann nicht zwei verschiedene Typen für denselben Template-Typ-Parameter angeben. Zum Beispieltemplate<class T>void h(T a, T b){},die aufrufende Anweisungh(2, 3.2)wird einen Fehler verursachen, weil die Anweisung für denselben Template-ParameterTzwei Typen angibt. Das erste Argument2legt den Template-Parameter T alsintfest, während das zweite Argument3.2den Template-Parameter alsdouble, die beiden Parametertypen sind inkonsistent, was einen Fehler verursacht.(Gilt für Funktionstemplates)
Originalversion des Autors: 1.2 ist für Funktionstemplates korrekt, berücksichtigt aber Klassentemplates nicht. Im Folgenden wird die Situation für Klassentemplates ergänzt.
Meine ergänzte Version 1.2 (für Klassentemplates):Wenn wir ein Klassenobjekt deklarieren als:A<int> a, zum Beispieltemplate<class T>T g(T a, T b){}, eine Aufrufanweisunga.g(2, 3.2)verursacht zur Compile-Zeit keinen Fehler, aber es wird eine Warnung geben, weil beim Deklarieren des Klassenobjekts bereitsTin denint-Typ umgewandelt wurde, während das zweite Argument3.2den Template-Parameter alsdouble, zur Laufzeit wird es3.2eine erzwungene Typkonvertierung zu3durchführen. Wenn wir das Objekt der Klasse deklarieren als:A<double> a, dann gibt es diesmal keine solche Warnung, weil vonintzudoubleist eine automatische Typkonvertierung.
Demonstrationsbeispiel 1:
TemplateDemo.h
Kompilierungsergebnis:
--------------------Configuration: TemplateDemo - Win32 Debug-------------------- Compiling... TemplateDemo.cpp G:\C++\CDaima\TemplateDemo\TemplateDemo.cpp(12) : warning C4244: 'argument' : conversion from 'const double' to 'int', possible loss of data TemplateDemo.obj - 0 error(s), 1 warning(s)
Run result:5
Aus dem obigen Testbeispiel können wir ersehen, dass es nicht so rigoros ist wie im Originalwerk des Autors! Dies ist nur mein persönliches Testergebnis! Bitte nehmen Sie eine praktische und wahrheitssuchende Haltung ein und überprüfen Sie es selbst!
2. Nicht-Typ-Parameter
2.1 Nicht-Typ-Template-Parameter:Ein Nicht-Typ-Template-Parameter ist ein Parameter eines eingebauten Typs, wie zum Beispieltemplate<class T, int a> class B{};wobeiint aist ein Nicht-Typ-Template-Parameter.
2.2 Nicht-Typ-Parameter sind konstante Werte innerhalb der Template-Definition; das heißt, Nicht-Typ-Parameter sind Konstanten innerhalb des Templates.
2.3, Nicht-Typ-Template-Parameter können nur integrale Typen, Zeiger und Referenzen sein, Typen wie double, String und String** sind nicht erlaubt.Aberdouble &,double *,Referenzen oder Zeiger auf Objekte sind gültig.
2.4, Das Argument für einen Nicht-Typ-Template-Parameter muss ein konstanter Ausdruck sein,das heißt, es muss zur Kompilierzeit berechenbar sein.
2.5 Hinweis:Jedes lokale Objekt, jede lokale Variable, die Adresse eines lokalen Objekts oder die Adresse einer lokalen Variablen ist kein konstanter Ausdruck und kann nicht als Argument für einen Nicht-Typ-Template-Parameter verwendet werden.Globale Zeigertypen, globale Variablen und globale Objekte sind ebenfalls keine konstanten Ausdrücke und können nicht als Argumente für Nicht-Typ-Template-Parameter verwendet werden.
2.6, ; A<b> m; das heißt, Array-zu-Zeiger-Konvertierung.。
2.7 、sizeofDas Ergebnis eines Ausdrucks ist ein konstanter Ausdruck und kann auch als Argument für einen Nicht-Typ-Template-Parameter verwendet werden.
2.8. Wenn der Template-Parameter ein Ganzzahltyp ist, muss das beim Aufrufen des Templates verwendete Argument vom Ganzzahltyp sein und während der Kompilierung eine Konstante sein. Zum Beispiel,template <class T, int a> class A{};Wenn esint b gibt, dann A<int, b> m;verursacht einen Fehler, weilbb keine Konstante ist. Wennconst int b, dann ist A<int, b> m; korrekt, weil zu diesem Zeitpunktbb eine Konstante ist.
2.9 、Nicht-Typ-Parameter werden im Allgemeinen nicht in Funktions-Templates verwendet.Zum Beispiel gibt es ein Funktions-Templatetemplate<class T, int a> void h(T b){}, wenn manh(2)zum Aufruf verwendet, tritt ein Fehler auf, der anzeigt, dass das Argument für den Nicht-Typ-Parameter a nicht abgeleitet werden kann. Für eine solche Template-Funktion können explizite Template-Argumente verwendet werden, um das Problem zu lösen, wie z. B. h<int, 3>(2), wodurch der Nicht-Typ-Parameter a auf die Ganzzahl 3 gesetzt wird. Explizite Template-Argumente werden später eingeführt.
2.10. Zulässige Konvertierungen zwischen Parameter und Argument von Nicht-Typ-Template-Parametern
1. Konvertierungen von Array zu Zeiger und von Funktion zu Zeiger sind zulässig. Zum Beispiel: template <int *a> class A{}; int b
2. Konvertierung des const-Qualifizierers. Zum Beispiel: template<const int *a> class A{}; int b; A<&b> m; das heißt, Konvertierung von int * zu const int *.
3. Promotion-Konvertierung. Zum Beispiel: template<int a> class A{}; const short b=2; A<b> m; das heißt, Promotion-Konvertierung von short nach int.
4. Integral-Konvertierung. Zum Beispiel: template<unsigned int a> class A{}; A<3> m; das heißt, Konvertierung von int nach unsigned int.
5. Übliche Konvertierungen.
Beispiel 1 zur Demonstration von Nicht-Typ-Parametern:
Der Benutzer legt die Größe des Stacks selbst fest und implementiert die zugehörigen Operationen des Stacks.
TemplateDemo.h
TemplateDemo.cpp

Demonstrationsbeispiel 2 für Nicht-Typ-Parameter:
TemplateDemo01.h
TemplateDemo01.cpp
Run result:-1
TemplateDemo01.cpp
Run result:1
TemplateDemo01.h
TempalteDemo01.cpp
Demonstrationsbeispiel 3 für Nicht-Typ-Parameter:
TemplateDemo02.cpp
Run result:

cout<<max<int>(2.1,2.2)<<endl; //显示指定的模板参数,会将函数函数直接转换为int.
Diese Anweisung verursacht eine Warnung:
--------------------Configuration: TemplateDemo02 - Win32 Debug-------------------- Compiling... TemplateDemo02.cpp G:\C++\CDaima\TemplateDemo02\TemplateDemo02.cpp(11) : warning C4244: 'argument' : conversion from 'const double' to 'const int', possible loss of data G:\C++\CDaima\TemplateDemo02\TemplateDemo02.cpp(11) : warning C4244: 'argument' : conversion from 'const double' to 'const int', possible loss of data TemplateDemo02.obj - 0 error(s), 2 warning(s)
IV. Standard-Template-Typparameter von Klassentemplates
1, Für die Typparameter von Klassentemplates können Standardwerte angegeben werden, für die Typparameter von Funktionstemplates jedoch nicht.Sowohl Funktions- als auch Klassentemplates können Standardwerte für Nicht-Typ-Template-Parameter bereitstellen.
2. Die Form von Standardwerten für Klassentemplate-Typparameter ist:template<class T1, class T2=int> class A{};für den zweiten Template-TypparameterT2geben Sieinteinen Standardwert vom Typ ... an
3. Standardwerte für Klassentemplate-Typparameter sind dasselbe wie Standardparameter von Funktionen. Wenn es mehrere Typparameter gibt, dann müssen alle Template-Parameter nach dem ersten Parameter, der einen Standardwert hat, ebenfalls Standardwerte haben. Zum Beispiel,template<class T1=int, class T2>class A{};es ist falsch, weilT1ein Standardwert für ... angegeben ist, währendT2kein Standardwert für ... festgelegt ist
4. Wenn man Member einer Klasse außerhalb des Klassentemplates definiert,templatesollte die Parameterliste nach 'template' die Standardparametertypen weglassen. Zum Beispiel:template<class T1, class T2=int> class A{public: void h();}; die Definitionsmethode isttemplate<class T1,class T2> void A<T1,T2>::h(){}。
Klassentemplate-Typparameter definieren:
Demonstrationsbeispiel 1:
TemplateDemo.h
TemplateDemo.cpp
Run result:5
Beispiel 1 für Standard-Template-Typparameter bei Klassentemplates:
TemplateDemo03.h
TemplateDemo03.cpp
Run result:2
Wenn man Member der Klasse außerhalb des Klassentemplates definiert, sollte die Parameterliste nach 'template' die Standardparametertypen weglassen. Wenn sie nicht weggelassen werden, verursacht das keinen Kompilierungsfehler, sondern gibt eine Warnung aus:
--------------------Configuration: TemplateDemo03 - Win32 Debug-------------------- Compiling... TemplateDemo03.cpp g:\c++\cdaima\templatedemo03\templatedemo03.h(12) : warning C4519: default template arguments are only allowed on a class template; ignored TemplateDemo03.obj - 0 error(s), 1 warning(s)
Originalautor:Standardwerte für Typparameter von Klassentemplates sind dieselben wie Standardparameter von Funktionen. Wenn es mehrere Typparameter gibt, müssen alle Templateparameter nach dem ersten Parameter, der einen Standardwert hat, ebenfalls Standardwerte haben. Zum Beispiel:template<class T1=int, class T2>class A{};es ist falsch, weilT1ein Standardwert für ... angegeben ist, währendT2kein Standardwert für ... festgelegt ist
Beispiel 2 zu Standard-Template-Typparametern für Klassentemplates:
TemplateDemo03.h
TemplateDemo03.cpp
Run result:9
TemplateDemo03.h
TemplateDemo03.cpp
Kompilierungsfehler:
--------------------Configuration: TemplateDemo03 - Win32 Debug-------------------- Compiling... TemplateDemo03.cpp g:\c++\cdaima\templatedemo03\templatedemo03.h(12) : error C2244: 'CeilDemo<T1,T2,T3>::ceil' : unable to resolve function overload g:\c++\cdaima\templatedemo03\templatedemo03.cpp(6) : error C2065: 'cd' : undeclared identifier g:\c++\cdaima\templatedemo03\templatedemo03.cpp(6) : error C2228: left of '.ceil' must have class/struct/union type Error executing cl.exe. TemplateDemo03.obj - 3 error(s), 0 warning(s)
Aus dem obigen Beispiel können wir sehen, dass ein Fehler auftritt, wenn wir versuchen, T2 und T3 als Typ double zu definieren (T1 ist standardmäßig als int definiert). Wenn wir also der Aussage des Autors folgen und T2 und T3 ebenfalls auf den Standardwert double setzen, tritt der Fehler dann immer noch auf? Betrachten Sie das folgende Beispiel:
Beispiel 4 zu Standard-Template-Typparametern für Klassentemplates:
TemplateDemo03.h
TemplateDemo03.cpp
Kompilierungsfehler:
--------------------Configuration: TemplateDemo03 - Win32 Debug-------------------- Compiling... TemplateDemo03.cpp g:\c++\cdaima\templatedemo03\templatedemo03.h(12) : error C2244: 'CeilDemo<T1,T2,T3>::ceil' : unable to resolve function overload g:\c++\cdaima\templatedemo03\templatedemo03.cpp(6) : error C2065: 'cd' : undeclared identifier g:\c++\cdaima\templatedemo03\templatedemo03.cpp(6) : error C2228: left of '.ceil' must have class/struct/union type Error executing cl.exe. TemplateDemo03.obj - 3 error(s), 0 warning(s)
An den Ergebnissen können wir sehen, dass es derselbe Fehler wie im vorherigen Beispiel ist. Aus den Beispielen können wir Folgendes zusammenfassen: Wenn ein Klassentemplate mehrere Typparameter hat und Standardwerte für Typparameter verwendet werden, sollten sie so weit wie möglich am Ende der Parameterliste stehen, und die Standardparametertypen müssen gleich sein. Wenn für den ersten Parameter ein Standardwert festgelegt ist, müssen auch alle Template-Parameter danach auf Standardwerte desselben Typs wie der erste Parameter gesetzt werden.(Erklärung: Ich bin auch neu in C++. Das Obige sind nur einige Fragen, die ich nach Demonstrationen mit Beispielen zum ursprünglichen Autor gestellt habe. Meine Beispiele mögen Mängel haben. Ich hoffe, dass Experten nicht zögern, Ratschläge zu geben, damit wir diesen Blog gemeinsam verbessern und eine Lernplattform für Anfänger wie mich bieten können!)
Als Nächstes prüfen wir: "Für Typparameter von Funktions-Templates können keine Standardwerte angegeben werden":
Beispiel 5 für Standard-Typparameter von Klassentemplates:
TemplateDemo04.cpp
Kompilierungsfehler:
--------------------Configuration: TemplateDemo04 - Win32 Debug-------------------- Compiling... TemplateDemo04.cpp g:\c++\cdaima\templatedemo04\templatedemo04.cpp(4) : error C2062: type 'int' unexpected Error executing cl.exe. TemplateDemo04.obj - 1 error(s), 0 warning(s)
Geänderte TemplateDemo.cpp
TemplateDemo.cpp
Run result:261.1
Das Demonstrationsbeispiel des ursprünglichen Autors lautet wie folgt:
Beispiel für Nicht-Typ-Parameter in Klassentemplates
Ursprüngliche Adresse:
https://www.cnblogs.com/gw811/archive/2012/10/25/2738929.html
http://www.cnblogs.com/gw811/archive/2012/10/25/2736224.html