1、类模板的泛指类型可以定义多个template<typenameT1,typenameT2>classTest{public:voidadd(T1a,T2,b);};使用时:Test<int,float>t1;//T1的泛指类型就是int,T2的泛指类型就是float。2、类模板的特化类型(1)意思就是如果定义了一个类模板,这个类模板的参数有多个,但是如果当使用这个类模板的时候,我们传递参数时,参数的类型是一样的话,编译器就会将类模板特化成一个参数的类模板。(2)类模板的特化分为:部分特化,和完全特化。部分特化:用特定规则约束类型参数,部分类型参数必须显示指定,根据类型参数分开实现类模板如:template特化后template<typenameT1,typnameT2><typenameT>classTestclassTest<T,T>//部分特化的约束条件{{};};当类型参数不同的时候,会选择用左边的那个类模板,当类型参数相同的时候。classTest<T,T>就是约束条件完全特化:完全显示指定类型参数如:template特化后template<typenameT1,typnameT2><>//完全特化时,不需要声明泛指类型classTestclassTest<int,int>//这个就是完全特化{{};};当使用类模板的时候,并且指定了所有的类型参数全都是一样的,比如int的时候,编译器就会将左边的类模板特化成右边的类模板,此时该类模板中就没有泛指类型了。当类型参数不同的时候,就会使用左边的类模板。(3)根据实验的例子,类模板的特化就是程序中有了一个左边的类模板的时候(这个类模板的有两个泛指类型),但是同时程序中我们又定义了一个同名的类模板,但是这个类模板的两个泛指类型都是一样的。这个时候,当我们在程序中使用这个类模板的时候,如果参数类型是不一样的,编译器就会使用左边的那个,如果参数类型是一样的时候,编译器就会使用右面的那个。编译器会认为右边的那个类模板,是左边的类模板的一种特化,编译器不会认为左边的类模板是一个新的类模板,只是一个左边类模板的一个特化,所以编译能够通过。总结:将一个类模板,根据不同的类型参数情况进行分开实现这个类模板,其实就是一个类模板的特化过程。例:#include<iostream>usingnamespacestd;template<typenameT1,typenameT2>classTest{public:voidadd(T1a,T2b){cout<<"voidadd(T1a,T2b)"<<endl;cout<<a+b<<endl;}};/*****************************************************部分特化*************************************************/template<typenameT>classTest<T,T>//这个地方加上了约束条件,虽然这个类模板跟上面的那个类模板同名,编译器不会认为这个类模板是一个新的类模板,而是上面类模板的一个特化形式,{//当我们使用Test类模板的时候,如果指定的参数类型不同的话,编译器就会使用上面的那个类模板实现,如果指定参数类型相同的话,编译器就会使用这个类模板的实现public:voidadd(Ta,Tb){cout<<"voidadd(Ta,Tb)"<<endl;cout<<a+b<<endl;}voidprint(void)//即使多出来了个print成员函数,编译也是通过的,所以是支持这种特化方式的{cout<<"classTest<T,T>"<<endl;}};/******************************************************完全特化**********************************************************/template<>//进行类模板的完全特化时,不用进行泛指类型的声明classTest<void*,void*>//当使用Test类模板时,参数类型都为void*时,就会使用这个实现。{public:voidadd(void*a,void*b){cout<<"voidadd(void*a,void*b)"<<endl;cout<<"Errorrunnottoaddbecausetypeisvoid*..."<<endl;}};/*****************************************将Test类模板特化出一个两个参数分别是指针的情况**********************************************/template<typenameT1,typenameT2>classTest<T1*,T2*>{public:voidadd(T1*a,T2*b){cout<<"voidadd(T1*a,T2*b)"<<endl;cout<<*a+*b<<endl;}};intmain(void){inta=1;doubleb=1.0;Test<int,float>t1;//使用的就是没有特化的Test类模板Test<long,long>t2;//使用的就是特化后的Test类模板Test<void*,void*>t3;Test<int*,double*>t4;t1.add(2,2.5);t2.add(10,10);t2.print();t3.add(&a,&b);t4.add(&a,&b);return0;}3、继续理解类模板的特化(1)类模板的特化的就是根据需要,将一个类模板进行分开来实现。特化只是模板的分开实现,本质上还是同一个类模板。特化类模板的使用方式是统一的,就是必须显示的指定每一个类型参数。(2)问题:类模板特化与重定义有区别吗?答:有区别,重定义和特化不同。在本质上,如果将一个类模板进行重定义,那么要么就是实现了一个新的类,要么就是最后会出现两个类模板。本质上不同。使用的时候不能进行统一使用,在使用时我们要考虑选择哪个。特化的本质是,只实现同一个类模板,只不过这个类模板是分开来实现的,这就是本质上的不同。在使用时是用统一的方式进行使用类模板和特化类,因为本质上都是实现了一个类模板,使用时编译器会根据不同的参数类型来选择去使用那个类模板还是特化类。所以类模板的特化就是将一个类模板进行分开来实现,这句话是非常重要的。(3)问题:函数模板可以特化吗?答:函数模板只支持类型参数的完全特化,不支持部分特化,也就是在函数名的后面显示的指定出具体的参数类型。如:函数模板的完全特化template<typenameT>boolEqual(Ta,Tb)//函数模板的定义{returna==b;}template<>boolEqual<void*>(void*,void*)//函数模板的完全特化{returna==b;}(4)工程中的建议:当需要重载函数模板的时候,我们要优先考虑使用模板特化的方式去分开实现一个函数模板,而是不用重载函数模板的方式去新的实现了一个函数,当模板特化无法满足要求的时候,在使用函数重载。工程中使用模板特化来代替类(函数)重定义。例:类模板的部分特化、完全特化,函数模板的完全特化。优先考虑使用特化的方式当需要将模板进行重定义添加功能时。#include<iostream>#include<string>usingnamespacestd;/**特化的方式实现一个类模板,本质就是分开实现类模板**/template<typenameT1,typenameT2>classWhy{public:voidprint(T1a,T2b){cout<<"voidprint(T1a,T2b)"<<endl;cout<<a<<""<<b<<endl;}};template<typenameT>classWhy<T,T>//为类模板的部分特化{public:voidprint(Ta,Tb){cout<<"voidprint(Ta,Tb)"<<endl;cout<<a<<""<<b<<endl;}};template<>classWhy<int,int>//为类模板的完全特化{public:voidprint(inta,intb){cout<<"voidprint(inta,intb)"<<endl;cout<<a<<""<<b<<endl;}};/**函数模板的特化只支持完全特化*实现一个函数模板,并且完全特化,也就是分开实现一个函数模板,这样叫做特化。*/template<typenameT>boolEqual(Ta,Tb){returna==b;}template<>//函数模板的完全特化,之所以要特化这个函数模板是因为,浮点数的比较不单纯的只用==来比较。boolEqual<double>(doublea,doubleb){constdoubledelta=0.00000000001;doubler=a-b;cout<<"boolEqual<double>(doublea,doubleb)"<<endl;return((-delta<r)&&(r<delta));}/**重载Equal函数的方式来达到比较浮点数的方法,但这种方式是不优先考虑的,因为这种方式,在使用的时候要考虑如何选择,要优先考虑使用特化的方式。*能使用特化的方式时,就不考虑使用这种函数重载的方式,不论对于类模板还是函数模板都是这样的,优先考虑使用特化的方式来分开实现,因为这样都是为了实现一个类模板或函数模板。*/boolEqual(doublea,doubleb){constdoubledelta=0.00000000001;doubler=a-b;cout<<"boolEqual(doublea,doubleb)"<<endl;return((-delta<r)&&(r<delta));}intmain(void){doublea=0.0,b=0.0;Why<int,double>w1;Why<string,string>w2;Why<int,int>w3;w2.print("why","fangqingqing");w1.print(1,2.2);w3.print(100,100);cout<<"Pleaseinputtwodoublenumber..."<<endl;cin>>a>>b;cout<<Equal<double>(a,b)<<endl;cin>>a>>b;cout<<Equal(a,b)<<endl;return0;}