目录绪言实例化显式实例化隐式实例化特化全特化类模板全特化函数模板全特化偏特化多个模板参数缺省的模板参数带参数包的类型参数非类型模板参数绪言模板是泛型编程实现的重要手段。关于模板的基本用法可以看我的这篇文章这里不再过多地赘述。本篇文章主要是面向掌握了C面向对象编程基本语法希望深入学习的读者。建议大家根据自身情况自行选择阅读与否。实例化模板实例化是模板的重要概念。什么是实例化呢在编写一个模板时我们并没有具体指定模板类型参数而是使用了一个占位符例如T。而当我们在创建一个类模板对象或者调用一个函数模板时无论是显式指定模板类型参数或者隐式推导系统最终都会得到我们定义的占位符在调用时的具体指代。这个过程就叫做模板实例化。模板实例化分为显式实例化和隐式实例化下面将分别讲述。显式实例化显式实例化即手动指定模板中的类型参数一般放在尖括号内置于函数名之后调用函数模板或者置于类名之后创建类模板对象。如果您还不能清晰地理解显式实例化请看下面的实例#includeiostreamusingnamespacestd;templatetypenameTclassmyclass{public:myclass(){};myclass(intp):id(p){};~myclass(){};public:intid;myclassToperator(constmyclassTb){myclassTret(this-idb.id);returnret;}};templatetypenameTTadd(T a,T b){returnab;}intmain(){myclassinta(5);myclassintb(6);coutaddmyclassint(a,b).idendl;return;}运行上面的代码将会输出以下结果11观察main()函数函数的一、二两行各定义了一个类模板对象我们显式地用int类型代替了占位符T函数的输出行调用了模板函数add我们显式地用类型myclass int代替了占位符T。在这个实例中我们都显式地指定了类型参数。这就是显式实例化。隐式实例化与显式实例化相对的是隐式实例化。隐式实例化即不明确指定类型参数而是系统通过函数的参数来推导类型参数。所以请注意由于定义一个类模板对象时不一定都有参数可供推导所以在C标准中隐式实例化是模板函数的专利不能用于类模板。这也就告诉我们一个类模板的名称并不是类型名一个指定了类型参数的类模板名称才是类型名例如在上面的实例中myclass是非法的类型名而myclass int是合法的。隐式实例化不必指定类型参数请看下面的实例它与上面的实例是等价的#includeiostreamusingnamespacestd;templatetypenameTclassmyclass{public:myclass(){};myclass(intp):id(p){};~myclass(){};public:intid;myclassToperator(constmyclassTb){myclassTret(this-idb.id);returnret;}};templatetypenameTTadd(T a,T b){returnab;}intmain(){myclassinta(5);myclassintb(6);coutadd(a,b).idendl;}相比于之前的实例这里只是把函数add()的调用更改了一下去除了函数名之后指定类型参数的内容。这就是隐式实例化。特化与模板实例化相似的概念还有模板特化。模板特化就是对于特殊的模板类型参数我们想实现不同的功能时补充的专门性的函数。特化分为全特化和偏特化。全特化全特化的一般形式为类模板全特化templatetypenameTclassa{public:T ori;//class body};templateclassaconstchar*{public:constchar*ori;//class body};函数模板全特化templatetypenameTTadd(T a,T b){returnab;}templatecharaddchar(chara,charb){returnab;}偏特化由于函数模板的偏特化可以通过重载实现所以函数模板没有偏特化只有类模板有偏特化。templatetypenameT1,typenameT2classa{public:T1 ori1;T2 ori2;//class body};templatetypenameTclassaconstchar*,T{public:constchar*ori1;T ori2;//class body};多个模板参数模板参数可以不止一个。例如在上面的实例中类a中就有两个类型参数T1和T2。在含有多个模板参数的模板参数列表中与函数参数类似地每个参数之间用,隔开。缺省的模板参数模板参数也可以缺省但所有缺省参数只能放在普通参数之后。模板参数可以只含有缺省参数但即使如此类模板对象创建时也要加上尖括号。请看下面的实例templatetypenameT1int,typenameT2intclassa{public:T1 A;T2 B;public:a(){};a(T1 first,T2 second):A(first),B(second){};~a(){};};intmain(){aClassa;acharClassb;adouble,doubleClassc;return0;}带参数包的类型参数在类型参数列表中的typename或class关键字后加上运算符...可以声明一个类型参数是参数包类型即该类型带有参数包。这样写的好处是可以与可变参数相结合编程。以下是一个实例#includevector#includetype_traits#includeiostreamusingnamespacestd;templatetypenameTclassmyclass{private:vectorTori;public:myclass(){};templatetypename..._Argsmyclass(_Args...args){vectorTtmp{forwardT(args)...};this-oritmp;}~myclass(){};public:voidprint(){for(inti0;ithis-ori.size();i){coutori[i] ;}coutendl;return;}};intmain(){myclassinta{1,2,3,4,5};a.print();return0;}运行上面的代码将会输出以下结果1 2 3 4 5非类型模板参数模板的参数不一定必须是类型参数也可以像函数参数一样是一个具体的对象。以下是一个实例展现了模板非类型参数实现变长数组的方法#includeiostreamusingnamespacestd;templatetypenameT,size_t Nclassarr{private:T ori[N];public:arr(){memset(ori,0,sizeof(ori));}~arr(){};};intmain(){arrint,5a;return0;}这里模板参数N就不是类型参数而是一个size_t类型的变量。调用时也与一般的类模板相同将模板参数置于尖括号内。希望大家多多支持多评论、多点赞、多收藏、多关注