一、模板参数再介绍初级模板知识模板参数是一个用来存放类型名称int double等内置类型和自定义类型名称的变量。在代码实现中使用模板参数写代码写一个函数或类会增加代码复用的能力。写出的函数或类被称为函数模板和类模板。 模板实例化编译器根据使用模板时指定的类型名称用这个类型名称来替代模板参数生成相应的函数或类。使用函数模板时通过传入参数类型实例化出相应的模板。 而使用类模板时需要显示说明模板参数类型才能实例化出相应的类。二、非类型模板参数前面提及的模板参数接受的都是类型的名字还有一种模板参数接受的是一个常数。看下面一段代码#includeiostreamtemplateclassT,size_t size10classarr{private:T arr[size];intlensize;public:arr();~arr();Toperator[](constarra);boolempty();};这个是CSTL中对数组的改造array的模拟实现未完成与c风格数组相比容器arr对越界访问更加严格。我们看到arr是一个类模板有两个模板参数第二个模板参数就是上面提及的非类型模板参数相当于C语言中常量的宏定义。但与宏定义相比较这样的类模板可以根据传入参数的不同自动调整常量不需要改变代码但是宏定义恰恰相反。举个arr的使用例子来体会非类型模板参数的用途#includeiostreamusingnamespacestd;#includearrayintmain(){arrayint,20arr{1,2,3,4,5};for(inti0;iarr.size();i){coutarr[i] ;//1 2 3 4 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}coutendl;return0;}三、函数模板的特化为什么需要引入特化就函数模板而言由于所有符合函数模板的参数列表中的每组参数并不都要根据函数模板实例化出的函数进行运算总有一两个特例要实现不同的方法所以引入模板特化。比如我想实现一个函数当两个参数是一切参数时判断第一个参数是否大于第二个参数。如果这样实现#includeiostreamusingnamespacestd;templateclassTboolfun(T a,T b){returnab}intmain(){inta10,b20;int*pbb,*paa;coutfun(a,b)endl;coutfun(pa,pb)endl;}存在指针比较是不是没有任何意义当参数为int*时我们特化一个函数模板让它返回指针所指向的最大的数#includeiostreamusingnamespacestd;templateclassTboolfun(T a,T b){returnab}templateboolfunint*(int*a,int*b){return*a*b;}intmain(){inta10,b20;int*pbb,*paa;coutfun(a,b)endl;coutfun(pa,pb)endl;}函数模板特化的语法1.前提是有一个相关的函数模板2.在特化函数模板之前加上template3.在特化声明函数时在函数名之后参数表之前加上特化的类型名称4.要求函数的其余部分除将模板参数特化替代外必须和原来函数一模一样否则就会编译报错。函数模板特化的特点由于函数模板的性质当定义一个将函数模板中所有模板参数替代成统一类型名称的函数fun时调用一个既可以走函数模板又可以直接调用fun时编译器会不再实例化函数模板直接调用fun。因此函数模板特化的作用不大大多数情况都可以通过定义一个将函数模板中所有模板参数替代成统一类型名称的函数fun调用fun直接解决问题但也不排除只有使用函数模板特化的方法才能解决问题的项目。使用上面提及的第二种常规方法解决之前需要函数模板特化才可以解决的问题#includeiostreamusingnamespacestd;templateclassTboolfun(T a,T b){returnab;}boolfun(int*a,int*b){return*a*b;}intmain(){inta10,b20;int*pbb,*paa;coutfun(a,b)endl;coutfun(pa,pb)endl;}四、类模板的特化1.全特化顾名思义就是将所有参数都特化和函数模板特化一样这里也强调一下函数模板特化的方式只有一种类模板特化可以全特化也可以半特化。示例代码#includeiostreamusingnamespacestd;templateclassT1,classT2classc1{private:T1 t1;T2 t2;public:c1(){coutT1,T2endl;}};templateclassc1int,int{private:intt1;intt2;public:c1(){coutint ,int endl;}};intmain(){c1int,doublecc;c1int,intc1;//T1,T2//int, int}和函数模板特化一致特化定义前要加上template特化声明时l类的名字和{}之间要加上特化的类型名称2.半特化别称偏特化先来看一下半特化的代码演示#includeiostreamusingnamespacestd;templateclassT1,classT2classc1{private:T1 t1;T2 t2;public:c1(){coutT1,T2endl;}};templateclassT1classc1T1,int{private:T1 t1;intt2;public:c1(){coutT1 ,int endl;}};intmain(){c1int,doublecc;c1int,intc1;//T1,T2//T1, int}半特化和全特化的不同在于半特化定义之前加的是template未特化的模板参数声明特化时类名称和{}之间加的是未特化的模板参数特化的模板参数这个排序要求和类模板定义之前的模板参数声明要一一对应下面的例子就是最好的说明#includeiostreamusingnamespacestd;templateclassT1,classT2,classT3classc1{private:T1 t1;T2 t2;T3 t3;public:c1(){coutT1,T2,T3endl;}};templateclassT1,classT3classc1T1,int,T3{private:T1 t1;intt2;public:c1(){coutT1 ,int,T3 endl;}};intmain(){c1int,double,intcc;c1int,int,doublec1;/*T1, T2, T3 T1, int, T3*/}半特化还有一种特殊的例子当被特化的类未指针或引用时templateclassT1,classT2classData{public:Data(){coutDataT1, T2endl;}private:T1 _d1;T2 _d2;}//两个参数偏特化为指针类型templatetypenameT1,typenameT2classDataT1*,T2*{public:Data(){coutDataT1*, T2*endl;}private:T1 _d1;T2 _d2;};//两个参数偏特化为引用类型templatetypenameT1,typenameT2classDataT1,T2{public:Data(constT1d1,constT2d2):_d1(d1),_d2(d2){coutDataT1, T2endl;}private:constT1_d1;constT2_d2;};voidtest2(){Dataint,doubled2;// 调用基础的模板Dataint*,int*d3;// 调用特化的指针版本Dataint,intd4(1,2);// 调用特化的指针版本}