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

#ifndef TEMPLATE_DEMO_HXX #define TEMPLATE_DEMO_HXX template<class T> class A{ public: T g(T a,T b); A(); }; #endif   TemplateDemo.cpp #include<iostream.h> #include "TemplateDemo.h" template<class T> A<T>::A(){} template<class T> T A<T>::g(T a,T b){ return a+b; } void main(){ A<int> a; cout<<a.g(2,3.2)<<endl; }

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

#ifndef TEMPLATE_DEMO_HXX #define TEMPLATE_DEMO_HXX template<class T,int MAXSIZE> class Stack{//MAXSIZE est défini par l'utilisateur lors de la création de l'objet private: T elems[MAXSIZE]; // Tableau contenant des éléments int numElems; // Nombre total actuel d'éléments public: Stack(); // Constructeur void push(T const&); // Empiler un élément void pop(); // Dépiler un élément T top() const; // Retourner l'élément au sommet de la pile bool empty() const{ // Renvoie si la pile est vide return numElems == 0; } bool full() const{ // Renvoie si la pile est pleine return numElems == MAXSIZE; } }; template <class T,int MAXSIZE> Stack<T,MAXSIZE>::Stack():numElems(0){ // Initialement, la pile ne contient aucun élément // Ne rien faire } template <class T,int MAXSIZE> void Stack<T, MAXSIZE>::push(T const& elem){ if(numElems == MAXSIZE){ throw std::out_of_range("Stack<>::push(): la pile est pleine"); } elems[numElems] = elem; // Ajouter l'élément ++numElems; // Augmenter le nombre d'éléments } template<class T,int MAXSIZE> void Stack<T,MAXSIZE>::pop(){ if (numElems <= 0) { throw std::out_of_range("Stack<>::pop(): pile vide"); } --numElems; // Diminuer le nombre d'éléments } template <class T,int MAXSIZE> T Stack<T,MAXSIZE>::top()const{ if (numElems <= 0) { throw std::out_of_range("Stack<>::top(): pile vide"); } return elems[numElems-1]; // Retourner le dernier élément } #endif

TemplateDemo.cpp

#include<iostream.h> #include <iostream> #include <string> #include <cstdlib> #include "TemplateDemo.h" int main(){ try { Stack<int,20> int20Stack; // Une pile pouvant stocker 20 éléments int Stack<int,40> int40Stack; // Une pile pouvant stocker 40 éléments int Stack<std::string,40> stringStack; // Une pile pouvant stocker 40 éléments string // Utilisez une pile pouvant stocker 20 éléments int int20Stack.push(7); std::cout << int20Stack.top() << std::endl; //7 int20Stack.pop(); // Utilisez une pile pouvant stocker 40 éléments string stringStack.push("hello"); std::cout << stringStack.top() << std::endl; //hello stringStack.pop(); stringStack.pop(); //Exception: Stack<>::pop<>: pile vide return 0; } catch (std::exception const& ex) { std::cerr << "Exception: " << ex.what() << std::endl; return EXIT_FAILURE; // Quitter le programme avec un indicateur d'ERREUR } }

Exemple 2 de démonstration de paramètre non-type :

TemplateDemo01.h

#ifndef TEMPLATE_DEMO_O1 #define TEMPLATE_DEMO_01 template<typename T> class CompareDemo{ public: int compare(const T&, const T&); }; template<typename T> int CompareDemo<T>::compare(const T& a,const T& b){ if((a-b)>0) return 1; else if((a-b)<0) return -1; else return 0; } #endif

TemplateDemo01.cpp

#include<iostream.h> #include "TemplateDemo01.h" void main(){ CompareDemo<int> cd; cout<<cd.compare(2,3)<<endl; }

Résultat de l'exécution :-1 

TemplateDemo01.cpp

#include<iostream.h> #include "TemplateDemo01.h" void main(){ CompareDemo<double> cd; cout<<cd.compare(3.2,3.1)<<endl; }

Résultat de l'exécution :1 

 

TemplateDemo01.h

#ifndef TEMPLATE_DEMO_O1 #define TEMPLATE_DEMO_01 template<typename T> class CompareDemo{ public: int compare(T&, T&); }; template<typename T> int CompareDemo<T>::compare(T& a,T& b){ if((a-b)>0) return 1; else if((a-b)<0) return -1; else return 0; } #endif

TempalteDemo01.cpp

#include<iostream.h> #include "TemplateDemo01.h" void main(){ CompareDemo<int> cd; int a=2,b=3; cout<<cd.compare(a,b)<<endl; }

Exemple 3 de démonstration de paramètre non-type:

TemplateDemo02.cpp

#include<iostream.h> template<typename T> const T& max(const T& a,const T& b){ return a>b ? a:b; } void main(){ cout<<max(2.1,2.2)<<endl;// L'argument de modèle est implicitement déduit comme double cout<<max<double>(2.1,2.2)<<endl;// Spécifier explicitement les paramètres de modèle. cout<<max<int>(2.1,2.2)<<endl;// Les paramètres de modèle spécifiés explicitement convertiront directement le paramètre de la fonction en int. }

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

#ifndef TEMPLATE_DEMO_HXX #define TEMPLATE_DEMO_HXX template<class T> class A{ public: T g(T a,T b); A(); }; #endif

TemplateDemo.cpp

#include<iostream.h> #include "TemplateDemo.h" template<class T> A<T>::A(){} template<class T> T A<T>::g(T a,T b){ return a+b; } void main(){ A<int> a; cout<<a.g(2,3)<<endl; }

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

#ifndef TEMPLATE_DEMO_03 #define TEMPLATE_DEMO_03 // Définir un modèle de classe avec un paramètre de type par défaut. Ici T2 est défini sur int par défaut. template<class T1,class T2=int> class CeilDemo{ public: int ceil(T1,T2); }; // Lors de la définition de membres de la classe en dehors du modèle de classe, la liste de paramètres après 'template' doit omettre les types de paramètres par défaut. template<class T1,class T2> int CeilDemo<T1,T2>::ceil(T1 a,T2 b){ return a>>b; } #endif

TemplateDemo03.cpp

#include<iostream.h> #include "TemplateDemo03.h" void main(){ CeilDemo<int> cd; cout<<cd.ceil(8,2)<<endl; }

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

#ifndef TEMPLATE_DEMO_03 #define TEMPLATE_DEMO_03 template<class T1=int,class T2,class T3> class CeilDemo{ public: int ceil(T1,T2,T3); }; template<class T1,class T2,class T3> int CeilDemo<T1,T2,T3>::ceil(T1 a,T2 b,T3 c){ return a+b+c; } #endif

TemplateDemo03.cpp

#include<iostream.h> #include "TemplateDemo03.h" void main(){ CeilDemo<int,int> cd; cout<<cd.ceil(2,3,4)<<endl; }

Résultat de l'exécution :9  

TemplateDemo03.h

#ifndef TEMPLATE_DEMO_03 #define TEMPLATE_DEMO_03 template<class T1=int,class T2,class T3> class CeilDemo{ public: double ceil(T1,T2,T3); }; template<class T1,class T2,class T3> double CeilDemo<T1,T2,T3>::ceil(T1 a,T2 b,T3 c){ return a+b+c; } #endif

TemplateDemo03.cpp

#include<iostream.h> #include "TemplateDemo03.h" void main(){ CeilDemo<double,double> cd; cout<<cd.ceil(2,3.1,4.1)<<endl; }

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

#ifndef TEMPLATE_DEMO_03 #define TEMPLATE_DEMO_03 template<class T1=int,class T2=double,class T3=double> class CeilDemo{ public: double ceil(T1,T2,T3); }; template<class T1,class T2,class T3> double CeilDemo<T1,T2,T3>::ceil(T1 a,T2 b,T3 c){ return a+b+c; } #endif

TemplateDemo03.cpp

#include<iostream.h> #include "TemplateDemo03.h" void main(){ CeilDemo<int,double,double> cd; cout<<cd.ceil(2,3.1,4.1)<<endl; }

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

#include<iostream.h> template<class T1,class T2,class T3> T1 sum(T1 a,T2 b,T3 c=int){ return a+b+c; } void main(){ cout<<sum<double,double>(1.1,2.1,3)<<endl; }

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

#include<iostream.h> template<class T1,class T2,class T3> T1 sum(T1 a,T2 b,T3 c){ return a+b+c; } void main(){ cout<<sum<double,short,int>(1.1,3,257)<<endl; }

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

// La déclaration ou la définition d'un modèle ne peut être effectuée qu'au niveau global, au niveau d'un espace de noms ou au niveau d'une classe. C'est-à-dire qu'elle ne peut pas être faite dans une portée locale ou à l'intérieur d'une fonction ; par exemple, un modèle ne peut pas être déclaré ou défini dans la fonction main. // Définition d'un modèle de classe template<class T>class A{public:T g(T a, T b); A();}; // Définir la classe A avec un paramètre de type de modèle de classe T template<class T1,class T2>class B{public:void g();}; // Définir la classe B avec deux paramètres de type de modèle de classe T1, T2 // Définir des paramètres de type par défaut pour les modèles de classe ; les paramètres de type par défaut ne conviennent pas aux modèles de fonction. template<class T1,class T2=int> class D{public: voidg();}; // Définir un modèle de classe avec des paramètres de type par défaut. Ici T2 est défini à int par défaut. //template<class T1=int, class T2>class E{}; // Erreur : si un paramètre de type par défaut est défini pour T1, alors tous les paramètres après T1 doivent aussi avoir des valeurs par défaut. // Les éléments suivants sont des définitions de paramètres non-type // Les paramètres non-type ne peuvent être que des types intégraux, des pointeurs et des références. Les types comme double, String, String ** ne sont pas autorisés. Cependant, double &, double * (références ou pointeurs vers des objets) sontcorrects.template<class T1,int a> class Ci{public:void g();}; // Définir un paramètre de modèle non-type, où le paramètre est un type intégral template<class T1,int &a>class Cip{public:void g();}; template<class T1,A<int>* m> class Cc{public:void g();}; // Définir un paramètre de modèle non-type, où le paramètre est un pointeur vers un objet de la classe A de type int. template<class T1,double*a>class Cd{public:void g();}; // Définir un paramètre de modèle non-type, où le paramètre est une référence de type double. class E{}; template<class T1,E &m> class Ce{}; // Un paramètre de modèle non-type est une référence à un objet. // Les déclarations suivantes de paramètres non-type sont incorrectes. //template<class T1,A m>class Cc{}; // Erreur : un objet ne peut pas être utilisé comme paramètre non-type ; le type d'un paramètre de modèle non-type ne peut être qu'une référence ou un pointeur vers un objet. //template<class T1,double a>class Cc{}; // Erreur : le paramètre d'un modèle non-type ne peut pas être de type double ; il peut être une référence vers double. //template<class T1,A<int> m>class Cc{}; // Erreur : le paramètre d'un modèle non-type ne peut pas être un objet ; il doit être une référence ou un pointeur vers un objet. Cette règle s'applique aussi aux paramètres de modèlesans exception.// Méthodes de définition de divers membres de classe en dehors du modèle de classe, // La fonction typeid(nom de variable).name() permet d'extraire le type du nom de variable. Par exemple, int a, alors cout<<typeid(a).name() affichera int. template<class T> A<T>::A(){cout<<"class A goucao"<<typeid(T).name()<<endl;} //Méthode pour définir un constructeur de classe en dehors du modèle de classe template<class T> T A<T>::g(T a,T b){cout<<"class A g(T a,T b)"<<endl;} //Définition des membres d'un modèle de classe en dehors du modèle de classe template<class T1,class T2> voidB<T1,T2>::g(){cout<<"class g f()"<<typeid(T1).name()<<typeid(T2).name()<<endl;} //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 en cours de définition. template<class T1,int a> voidCi<T1,a>::g(){cout<<"class Ci g()"<<typeid(T1).name()<<endl;} template<class T1,int &a> voidCip<T1,a>::g(){cout<<"class Cip g()"<<typeid(T1).name()<<endl;} //Lors de la définition des membres de classe en dehors de la classe, les paramètres template après template doivent correspondre aux paramètres template de la classe définie. template<class T1,A<int> *m> voidCc<T1,m>::g(){cout<<"class Cc g()"<<typeid(T1).name()<<endl;} template<class T1,double* a> voidCd<T1,a>::g(){cout<<"class Cd g()"<<typeid(T1).name()<<endl;} //Méthode pour définir des membres en dehors de la classe pour une classe template avec des paramètres de type par défaut. //Lors de la définition des membres de classe en dehors de la classe, les valeurs par défaut dans la liste des paramètres template doivent être omises. template<class T1,class T2> voidD<T1,T2>::g(){cout<<"class D g()"<<endl;} //template<class T1,class T2=int> void D<T1,T2>::g(){cout<<"class D k()"<<endl;} //erreur, lors de la définition d'un modèle avec un type par défaut en dehors du modèle de classe, leparamètre formel, dansle modèle,la valeur par défaut dans la liste des paramètres doit être omise.//Définir quelques variables globales. int e=2; doubleed=2.2; double*pe=&ed; A<int> mw; A<int> *pec=&mw; E me; //la fonction main commence int main() { // template<class T>void h(){} //erreur, les déclarations ou définitions de modèle ne peuvent apparaître que dans une portée globale, de namespace ou de classe. C'est-à-dire qu'elles ne peuvent pas apparaître dans une portée locale ou à l'intérieur d'une fonction. //A<2> m; //erreur, il n'y a pas de déduction d'arguments pour les modèles de classe ; le type doit être explicitement spécifié entre chevrons. //Exemple d'appel d'un modèle de classe A<int> ma; //Sortie "class A goucao int" crée l'objet ma du modèle de classe A avec le type int. B<int,int> mb; mb.g(); //Sortie "class B g() int int" crée l'objet mb du modèle de classe B, avec les paramètres de type T1 et T2 définis sur int. //Appel d'un paramètre non-type //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. Tout objet local, variable locale, adresse d'un objet local, localles adresses de variables ne sont pas des expressions constantes et ne peuvent pas être utilisées comme arguments pour des paramètres de modèle non-type. Les types pointeur globaux, les variables globales et les objets globaux ne sont pas non plus des expressions constantes et ne peuvent pas//L'adresse ou la référence d'une variable globale, l'adresse ou la référence d'un objet global, ou une variable de type const est une expression constante et peut être utilisée comme argument pour un paramètre de modèle non-type. //La méthode pour appeler un paramètre non-type int est nommée Ci, déclarée comme template<class T1,int a> class Ci Ci<int,3>//Correct, la valeur R est une constante int, sortie "class Ci g() int" const int a2=3; Ci<int,a2> mci1; mci1.g(); //Correct, car a2 est une constante const ici. Sortie "class Ci g() int" //Ci<int,a> mci; //erreur, la variable int a est une variable locale et non une expression constante. //Ci<int,e> mci; //erreur, la variable globale int e n'est pas non plus une expression constante. //La méthode pour appeler un paramètre non-type int& a pour nom de classe Cip, déclarée comme template<class T1,int &a>class Cip Cip<int,e> mcip; //Correct, la référence ou l'adresse d'une variable globale est une expression constante. //Cip<int,a> mcip1; //erreur, la référence ou l'adresse d'une variable locale n'est pas une expression constante. //La méthode pour appeler un paramètre non-type double* a pour nom de classe Cd, déclarée comme template<class T1,double *a>class Cd Cd<int,&ed> mcd; //Correct, la référence ou l'adresse d'une variable globale est une expression constante. //Cd<int,pe> mcd1; //erreur, un pointeur de variable globale n'est pas une expression constante. //double dd=3.3; //erreur, l'adresse d'une variable locale n'est pas une expression constante et ne peut pas être utilisée comme argument pour un paramètre non-type //Cd<int,&e> mcd; //erreur, bien que certaines conversions soient autorisées pour les paramètres non-type, cette conversion ne peut pas être effectuée. //La méthode pour appeler un objet paramètre de type de modèle A<int>* a pour nom de classe Cc, déclarée comme template<class T1,A<int>* m> class Cc Cc<int,&mw> mcc; mcc.g(); //Correct, l'adresse ou la référence d'un objet global est une expression constante. //Cc<int,&ma> mcc; //erreur, l'adresse ou la référence d'une variable locale n'est pas une expression constante. //Cc<int,pec> mcc2; //erreur, un pointeur vers un objet global n'est pas une expression constante. //La méthode pour appeler un paramètre non-type qui est une référence à un objet E& a pour nom de classe Ce. Forme de déclaration : template<class T1,E &m> class Ce E me1; //Ce<int,me1> mce1; //erreur, un objet local n'est pas une expression constante Ce<int,me> mce; //Correct, le pointeur ou la référence vers un objet global est une expression constante. //Exemple de conversions pour des paramètres non-type, nom de classe Ci //Les paramètres non-type autorisent les conversions tableau-vers-pointeur, fonction-vers-pointeur, de qualificateur const, de promotion, intégrales, et les conversions habituelles. const short s=3; Ci<int,s> mci4†//Correct, bien que short et int ne correspondent pas exactement, ici short peut être converti en int

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