Les templates sont un outil permettant à C++ de prendre en charge le polymorphisme paramétrique. En utilisant des templates, les utilisateurs peuvent déclarer un modèle général pour des classes ou des fonctions, permettant à certains membres de données d'une classe, ou aux paramètres et valeurs de retour de fonctions membres, de prendre des types arbitraires.
Un template est un outil qui paramètre les types ;
Il existe généralement deux formes : les templates de fonctions et les templates de classes ;
Les templates de fonctions ciblent les fonctions qui ne diffèrent que par les types de paramètres ;
Les modèles de classe ciblent des classes qui ne diffèrent que par les types des membres de données et des fonctions membres.
Le but de l'utilisation de modèles est de permettre aux programmeurs d'écrire du code indépendant du type. Par exemple, si vous écrivez une fonction swap qui échange deux variables int, cette fonction ne peut traiter que des int. Elle ne peut pas traiter des types tels que double ou char. Pour échanger ces types, vous devriez écrire une autre fonction swap. Le but de l'utilisation de modèles est de rendre l'implémentation du programme indépendante du type. Par exemple, une fonction modèle swap peut gérer à la fois des échanges de int et de double. Les modèles peuvent être appliqués aux fonctions et aux classes. Ils sont présentés séparément ci-dessous.
Remarque :La déclaration ou la définition d'un modèle ne peut se produire que dans la portée globale, de namespace ou de classe. C'est-à-dire qu'elle ne peut pas se produire dans une portée locale ou à l'intérieur d'une fonction ; par exemple, vous ne pouvez pas déclarer ou définir un modèle dans la fonction main.
I. Forme générale des modèles de fonctions
1. Format d'un modèle de fonction :
template <class 形参名,class 形参名,......> 返回类型 函数名(参数列表)
{
函数体
}
Parmi ceux-ci, template et class sont des mots-clés. class peut être remplacé par le mot-clé typename. Ici, typename et class ne présentent aucune différence. Les paramètres à l'intérieur de <> sont appelés paramètres de modèle. Les paramètres de modèle sont très similaires aux paramètres de fonction. Les paramètres de modèle ne peuvent pas être vides. Une fois qu'une fonction modèle est déclarée, vous pouvez utiliser les noms des paramètres de modèle pour déclarer des variables membres et des fonctions membres dans la classe ; c'est-à-dire que partout où des types intégrés peuvent être utilisés dans cette fonction, les noms des paramètres de modèle peuvent être utilisés. Les paramètres de modèle doivent être initialisés par les arguments de modèle fournis lors de l'appel de la fonction modèle. Une fois que le compilateur détermine le type réel de l'argument de modèle, on dit qu'il a instancié une instance du modèle de fonction. Par exemple, la forme modèle de la fonction swap est :
template <class T> void swap(T& a, T& b){},
Lorsqu'une telle fonction modèle est appelée, le type T est remplacé par le type utilisé dans l'appel, par exempleswap(a,b)oùaetbsontinttype, et à ce stade les paramètres de la fonction modèle swapTserontintremplacés, et la fonction modèle devientswap(int &a, int &b). Et lorsqueswap(c,d)oùcetdOuidoubletype, la fonction modèle sera remplacée parswap(double &a, double &b), réalisant ainsi un code dont l'implémentation de fonction est indépendante du type.
2. Remarque : pour les fonctions modèles, il n'existe pash(int,int)un tel appel,Le type des paramètres de modèle ne peut pas être spécifié dans les arguments d'un appel de fonction. Les appels aux fonctions modèles doivent utiliserla déduction des argumentsà effectuer, c'est-à-dire que seuls h(2,3)de tels appels peuvent être faits, ouint a, b; h(a,b)。
Des exemples de démonstration des fonctions modèles seront présentés ci-dessous !
II. Forme générale des classes modèles
1. Le format d'une classe modèle est :
template<class 形参名,class 形参名,…> class 类名
{ ... };
Les classes modèles et les fonctions modèles commencent toutes deux par template suivi d'une liste de paramètres de modèle. Les paramètres de modèle ne peuvent pas être vides. Une fois qu'une classe modèle est déclarée, vous pouvez utiliser les noms des paramètres de la classe modèle pour déclarer des variables membres et des fonctions membres dans la classe. Autrement dit, partout où des types intégrés peuvent être utilisés dans la classe, les noms des paramètres de modèle peuvent être utilisés pour la déclaration. Par exemple
template<class T> class A{public: T a; T b; T hy(T c, T &d);};
Dans la classe A, deux variables membres a et b de type T sont déclarées, et une fonction hy de type de retour T avec deux paramètres de type T est également déclarée.
2. Création d'un objet de classe modèle : Par exemple, une classe modèleA, alors la méthode pour créer un objet en utilisant la classe modèle estA<int> m;Après la classeAsuivie d'un<>chevron et remplissez les types correspondants à l'intérieur. De cette façon, la classeApartout où des paramètres de modèle sont utilisés dans la classe, ils seront remplacés parint. Lorsqu'une classe modèle a deux paramètres de modèle, la méthode pour créer un objet estA<int, double> m;Séparez les types par des virgules.
3. Pour les modèles de classe, les types des paramètres de modèle doivent être explicitement spécifiés entre les chevrons après le nom de la classe. Par exempleA<2> m;Définir le paramètre de modèle surintest incorrect (Erreur de compilation : error C2079: 'a' uses undefined class 'A<int>'),Les paramètres de modèle de classe n'ont pas le problème de déduction des arguments.Autrement dit, une valeur entière ne peut pas être2déduite commeinttype et passée au paramètre de modèle. Pour définir le paramètre de modèle de classe surinttype, il doit être spécifié comme ceciA<int> m。
4. La méthode pour définir des fonctions membres en dehors d'un modèle de classe est :
template<模板形参列表> 函数返回类型 类名<模板形参名>::函数名(参数列表){函数体},
Par exemple, si la classe A avec deux paramètres de modèle T1 et T2 contient une fonction void h(), la syntaxe pour définir cette fonction est :
template<class T1,class T2> void A<T1,T2>::h(){}。
Remarque :Lors de la définition de membres de classe en dehors de la classe, les paramètres de modèle après template doivent être cohérents avec les paramètres de modèle de la classe définie.
5. Rappel encore une fois : la déclaration ou la définition d'un modèle ne peut avoir lieu que dans une portée globale, d'espace de noms ou de classe. C'est-à-dire qu'elle ne peut pas avoir lieu dans une portée locale ou à l'intérieur d'une fonction ; par exemple, elle ne peut pas se trouver dans la fonctionmainpour déclarer ou définir un modèle.
III. Paramètres de modèle
Il existe trois types de paramètres de modèle : les paramètres de type, les paramètres non-type et les paramètres modèles.
1. Paramètres de type
1.1 Paramètres de type de modèle :Un paramètre de type est composé du mot-clé class ou typename suivi d'un spécificateur, comme par exempletemplate<class T> void h(T a){}; oùTest un paramètre de type. Le nom du paramètre de type est déterminé par l'utilisateur lui-même.Un paramètre de modèle représente un type inconnu.Un paramètre de type de modèle peut être utilisé comme spécificateur de type n'importe où dans le modèle, exactement de la même manière que les spécificateurs de type intégrés ou les spécificateurs de type de classe ; c'est-à-dire qu'il peut être utilisé pour spécifier des types de retour, des déclarations de variables, etc.
Version originale de l'auteur :1.2, Vous ne pouvez pas spécifier deux types différents pour le même paramètre de type de modèle. Par exemple,template<class T>void h(T a, T b){},l'instruction d'appelh(2, 3.2)provoquera une erreur, car l'instruction spécifie, pour le même paramètre de modèle,Tdeux types. Le premier argument2spécifie le paramètre de modèle T comme étantint, tandis que le second argument3.2spécifie le paramètre de modèle comme étantdouble, les deux types de paramètres sont incohérents, provoquant une erreur.(S'applique aux modèles de fonctions)
Version originale de l'auteur : 1.2 est correct pour les modèles de fonctions, mais il ignore les modèles de classes. Ci-dessous, la situation pour les modèles de classes sera complétée.
Ma version supplémentaire 1.2 (pour les modèles de classes) :Lorsque nous déclarons un objet de classe comme :A<int> a, par exempletemplate<class T>T g(T a, T b){}, une instruction d'appela.g(2, 3.2)ne provoquera pas d'erreur à la compilation, mais il y aura un avertissement, car lors de la déclaration de l'objet de classe, il a déjà étéTconverti eninttype, tandis que le second argument3.2spécifie le paramètre de modèle comme étantdouble, à l'exécution, il va3.2effectuer une conversion de type forcée vers3. Lorsque nous déclarons l'objet de la classe comme :A<double> a, à ce moment-là, il n'y aura pas un tel avertissement, car deintversdoubleest une conversion de type automatique.
Exemple de démonstration 1 :
TemplateDemo.h
Résultat de la compilation :
--------------------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)
Résultat de l'exécution :5
D'après l'exemple de test ci-dessus, nous pouvons voir que ce n'est pas aussi rigoureux que dans le travail original de l'auteur ! Ce n'est que mon résultat de test personnel ! Veuillez adopter une attitude pratique et à la recherche de la vérité, et le vérifier vous-même !
2. Paramètres non-type
2.1 Paramètres de modèle non-type :Un paramètre de modèle non-type est un paramètre de type intégré, tel quetemplate<class T, int a> class B{};oùint aest un paramètre de modèle non-type.
2.2 Les paramètres non-type sont des valeurs constantes à l'intérieur de la définition du modèle ; c'est-à-dire que les paramètres non-type sont des constantes à l'intérieur du modèle.
2.3, Non-typetemplateparamètres ne peuvent être que des types intégraux, des pointeurs et des références, les types tels que double, String et String** ne sont pas autorisés.Maisdouble &,double *,Les références ou pointeurs vers des objets sont valides.
2.4, L'argument d'un paramètre de modèle non-type doit être une expression constante,c'est-à-dire qu'il doit être calculable au moment de la compilation.
2.5 Remarque :Tout objet local, variable locale, adresse d'un objet local ou adresse d'une variable locale n'est pas une expression constante et ne peut pas être utilisé comme argument pour un paramètre de modèle non-type.Les types de pointeurs globaux, les variables globales et les objets globaux ne sont pas non plus des expressions constantes et ne peuvent pas être utilisés comme arguments pour des paramètres de modèle non-type.
2.6, ; A<b> m; c'est-à-dire une conversion de tableau en pointeur.。
2.7 、sizeofLe résultat d'une expression est une expression constante, et il peut également être utilisé comme argument pour un paramètre de modèle non-type.
2.8. Lorsque le paramètre de modèle est de type entier, l'argument utilisé lors de l'appel du modèle doit être de type entier et doit être une constante lors de la compilation. Par exemple,template <class T, int a> class A{};S'il existeint b, alors A<int, b> m;provoquera une erreur, carbb n'est pas une constante. Siconst int b, alors A<int, b> m; est correct, car à ce momentbb est une constante.
2.9 、Les paramètres non-type ne sont généralement pas utilisés dans les modèles de fonctions.Par exemple, il existe un modèle de fonctiontemplate<class T, int a> void h(T b){}, si l'on utiliseh(2)pour l'appeler, une erreur se produira indiquant que l'argument du paramètre non-type a ne peut pas être déduit. Pour une telle fonction modèle, des arguments de modèle explicites peuvent être utilisés pour résoudre le problème, comme h<int, 3>(2), qui définit le paramètre non-type a à l'entier 3. Les arguments de modèle explicites seront présentés plus tard.
2.10. Conversions autorisées entre le paramètre et l'argument des paramètres de modèle non-type
1. Les conversions de tableau en pointeur et de fonction en pointeur sont autorisées. Par exemple : template <int *a> class A{}; int b
2. Conversion du qualificateur const. Par exemple : template<const int *a> class A{}; int b; A<&b> m; c'est-à-dire une conversion de int * en const int *.
3. Conversion par promotion. Par exemple : template<int a> class A{}; const short b=2; A<b> m; c'est-à-dire une conversion par promotion de short vers int.
4. Conversion intégrale. Par exemple : template<unsigned int a> class A{}; A<3> m; c'est-à-dire une conversion de int vers unsigned int.
5. Conversions usuelles.
Exemple de démonstration d'un paramètre non-type 1 :
L'utilisateur spécifie lui-même la taille de la pile et implémente les opérations associées à la pile.
TemplateDemo.h
TemplateDemo.cpp

Exemple 2 de démonstration de paramètre non-type :
TemplateDemo01.h
TemplateDemo01.cpp
Résultat de l'exécution :-1
TemplateDemo01.cpp
Résultat de l'exécution :1
TemplateDemo01.h
TempalteDemo01.cpp
Exemple 3 de démonstration de paramètre non-type:
TemplateDemo02.cpp
Résultat de l'exécution :

cout<<max<int>(2.1,2.2)<<endl; //显示指定的模板参数,会将函数函数直接转换为int.
Cette instruction provoquera un avertissement :
--------------------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. Paramètres de type de modèle par défaut des modèles de classe
1, Des valeurs par défaut peuvent être fournies pour les paramètres de type des modèles de classe, mais des valeurs par défaut ne peuvent pas être fournies pour les paramètres de type des modèles de fonction.Les modèles de fonction et les modèles de classe peuvent tous deux fournir des valeurs par défaut pour les paramètres de modèle non-type.
2. La forme des valeurs par défaut pour les paramètres de type des modèles de classe est :template<class T1, class T2=int> class A{};pour le deuxième paramètre de type de modèleT2fournirintune valeur par défaut de type ...
3. Les valeurs par défaut des paramètres de type des modèles de classe sont identiques aux paramètres par défaut des fonctions. S'il y a plusieurs paramètres de type, alors tous les paramètres de modèle après le premier paramètre qui a une valeur par défaut doivent aussi avoir des valeurs par défaut. Par exemple,template<class T1=int, class T2>class A{};c'est incorrect, carT1une valeur par défaut est donnée pour ..., alors queT2aucune valeur par défaut n'est définie pour ...
4. Lors de la définition de membres d'une classe en dehors du modèle de classe,templatela liste de paramètres après 'template' doit omettre les types de paramètres par défaut. Par exemple,template<class T1, class T2=int> class A{public: void h();}; la méthode de définition esttemplate<class T1,class T2> void A<T1,T2>::h(){}。
Définir les paramètres de type du modèle de classe :
Exemple de démonstration 1 :
TemplateDemo.h
TemplateDemo.cpp
Résultat de l'exécution :5
Exemple 1 de paramètres de type de modèle par défaut pour les modèles de classe :
TemplateDemo03.h
TemplateDemo03.cpp
Résultat de l'exécution :2
Lors de la définition des membres de la classe en dehors du modèle de classe, la liste des paramètres après 'template' doit omettre les types de paramètres par défaut. Si elle n'est pas omise, cela ne provoquera pas d'erreur de compilation mais émettra un avertissement :
--------------------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)
Auteur original :Les valeurs par défaut des paramètres de type de modèle de classe sont les mêmes que les paramètres par défaut des fonctions. S'il y a plusieurs paramètres de type, alors tous les paramètres de modèle après le premier paramètre qui a une valeur par défaut doivent également avoir des valeurs par défaut. Par exemple,template<class T1=int, class T2>class A{};c'est incorrect, carT1une valeur par défaut est donnée pour ..., alors queT2aucune valeur par défaut n'est définie pour ...
Exemple 2 de paramètres de type de modèle par défaut pour les modèles de classe :
TemplateDemo03.h
TemplateDemo03.cpp
Résultat de l'exécution :9
TemplateDemo03.h
TemplateDemo03.cpp
Erreur de compilation :
--------------------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)
D'après l'exemple ci-dessus, nous pouvons voir que lorsque nous essayons de définir T2 et T3 comme types double, une erreur se produit (T1 est défini comme int par défaut). Donc, si nous suivons l'affirmation de l'auteur et définissons également T2 et T3 sur la valeur par défaut double, l'erreur se produira-t-elle encore ? Regardez l'exemple suivant :
Exemple 4 de paramètres de type de modèle par défaut pour les modèles de classe :
TemplateDemo03.h
TemplateDemo03.cpp
Erreur de compilation :
--------------------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)
D'après les résultats, nous pouvons voir qu'il s'agit de la même erreur que dans l'exemple précédent. À partir des exemples, nous pouvons résumer comme suit : si un modèle de classe a plusieurs paramètres de type et que des valeurs par défaut de paramètres de type sont utilisées, elles doivent être placées à la fin de la liste des paramètres autant que possible, et les types des paramètres par défaut doivent être identiques. Si une valeur par défaut est définie pour le premier paramètre, alors tous les paramètres de modèle qui le suivent doivent également être définis avec des valeurs par défaut du même type que le premier paramètre.(Déclaration : je suis également nouveau en C++. Ce qui précède ne sont que quelques questions que j'ai soulevées à propos de l'auteur original après des démonstrations avec des exemples. Mes exemples peuvent présenter des lacunes. J'espère que les experts n'hésiteront pas à donner des conseils, afin que nous puissions améliorer ensemble ce blog et fournir une plateforme d'apprentissage aux novices comme moi !)
Ensuite, vérifions que « des valeurs par défaut ne peuvent pas être fournies pour les paramètres de type des modèles de fonction » :
Exemple 5 des paramètres de type de modèle par défaut pour les modèles de classe :
TemplateDemo04.cpp
Erreur de compilation :
--------------------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)
TemplateDemo.cpp modifié
TemplateDemo.cpp
Résultat de l'exécution :261.1
L'exemple de démonstration de l'auteur original est le suivant :
Exemple de paramètres non-type dans les modèles de classe
Adresse d'origine :
https://www.cnblogs.com/gw811/archive/2012/10/25/2738929.html
http://www.cnblogs.com/gw811/archive/2012/10/25/2736224.html