深入分析C++模板特化与偏特化
1.模板特化
1.1概述
模板特化(templatespecialization)不同于模板的实例化,模板参数在某种特定类型下的具体实现称为模板的特化。模板特化有时也称之为模板的具体化,分别有函数模板特化和类模板特化。
1.2函数模板特化
函数模板特化是在一个统一的函数模板不能在所有类型实例下正常工作时,需要定义类型参数在实例化为特定类型时函数模板的特定实现版本。查看如下例子。
#includeusingnamespacestd; template TMax(Tt1,Tt2) { return(t1>t2)?t1:t2; } typedefconstchar*CCP; template<>CCPMax (CCPs1,CCPs2) { return(strcmp(s1,s2)>0)?s1:s2; } intmain() { //调用实例:intMax (int,int) inti=Max(10,5); //调用显示特化:constchar*Max (constchar*,constchar*) constchar*p=Max ("very","good"); cout<<"i:"< 程序正常编译运行结果:
i:10
p:very在函数模板显示特化定义(ExplicitSpecializationDefinition)中,显示关键字template和一对尖括号<>,然后是函数模板特化的定义。该定义指出了模板名、被用来特化模板的模板实参,以及函数参数表和函数体。在上面的程序中,如果不给出函数模板Max
在T为constchar*时的特化版本,那么在比较两个字符串的大小时,比较的是字符串的起始地址的大小,而不是字符串的内容在字典序中先后次序。 除了定义函数模板特化版本外,还可以直接给出模板函数在特定类型下的重载形式(普通函数)。使用函数重载可以实现函数模板特化的功能,也可以避免函数模板的特定实例的失效。例如,把上面的模板特化可以改成如下重载函数。
typedefconstchar*CCP; CCPMax(CCPs1,CCPs2) { return(strcmp(s1,s2)>0)?s1:s2; }程序运行结果和使用函数模板特化相同。但是,使用普通函数重载和使用模板特化还是有不同之处,主要表现在如下两个方面:
(1)如果使用普通重载函数,那么不管是否发生实际的函数调用,都会在目标文件中生成该函数的二进制代码。而如果使用模板的特化版本,除非发生函数调用,否则不会在目标文件中包含特化模板函数的二进制代码。这符合函数模板的“惰性实例化”准则。
(2)如果使用普通重载函数,那么在分离编译模式下,应该在各个源文件中包含重载函数的申明,否则在某些源文件中就会使用模板函数,而不是重载函数。1.3类模板特化
类模板特化类似于函数模板的特化,即类模板参数在某种特定类型下的具体实现。考察如下代码。
#includeusingnamespacestd; template classA { Tnum; public: A() { num=T(6.6); } voidprint() { cout<<"A'num:"< classA { char*str; public: A(){ str="A'specialdefinition"; } voidprint(){ cout< a1;//显示模板实参的隐式实例化 a1.print(); A a2;//使用特化的类模板 A2.print(); } 程序输出结果如下:
A'num:6
A'specialdefinition2.模板偏特化
2.1概述
模板偏特化(templatepartitialspecialization)是模板特化的一种特殊情况,指指定模板参数而非全部模板参数,或者模板参数的一部分而非全部特性,也称为模板部分特化。与模板偏特化相对的是模板全特化,指对所有的模板参数进行特化。模板全特化与模板偏特化共同组成模板特化。
模板偏特化主要分为两种,一种是指对部分模板参数进行全特化,另一种是对模板参数特性进行特化,包括将模板参数特化为指针、引用或是另外一个模板类。
2.2函数模板偏特化
假如我们有一个compare函数模板,在比较数值类型时没有问题,如果传入的数值的地址,我们需要两个数值的大写,而非比较传入的地址大小。此时我们需要对compare函数模板进行偏特化。考察如下代码:
#include#include usingnamespacestd; //函数模板 template voidcompare(Tnum1,Nnum2) { cout<<"standardfunctiontemplate"< num2) cout<<"num1:"< num2:"< voidcompare(intnum1,Nnum2) { cout<<"partitialspecialization"< num2) cout<<"num1:"< num2:"< voidcompare(T*num1,N*num2) { cout<<"newpartitialspecialization"< *num2) cout<<"num1:"<<*num1<<">num2:"<<*num2< voidcompare(std::vector &vecLeft,std::vector &vecRight) { cout<<"tovectorpartitialspecialization"< vecRight.size()) cout<<"vecLeft.size()"< vecRight.size():"< (30,31);//调用非特化版本compare (intnum1,intnum2) compare(30,'1');//调用偏特化版本compare (intnum1,charnum2) inta=30; charc='1'; compare(&a,&c);//调用偏特化版本compare (int*num1,char*num2) vector vecLeft{0}; vector vecRight{1,2,3}; compare (vecLeft,vecRight);//调用偏特化版本compare (int*num1,char*num2) } 程序输出结果如下:
standardfunctiontemplate
num1:30<=num2:31
partitialspecialization
num1:30<=num2:1
newpartitialspecialization
num1:30<=num2:1
tovectorpartitialspecialization
vecLeft.size()1<=vecRight.size():32.3类模板偏特化
类模板的偏特化与函数模板的偏特化类似。考察如下代码:
#include#include usingnamespacestd; //类模板 template classTestClass { public: staticboolcomp(Tnum1,Nnum2) { cout<<"standardclasstemplate"< classTestClass { public: staticboolcomp(intnum1,Nnum2) { cout<<"partitialspecialization"< classTestClass { public: staticboolcomp(T*num1,N*num2) { cout<<"newpartitialspecialization"< classTestClass ,vector > { public: staticboolcomp(constvector &vecLeft,constvector &vecRight) { cout<<"tovectorpartitialspecialization"< ::comp('0','1')< ::comp(30,'1')< ::comp(&a,&c)< vecLeft{0}; vector vecRight{1,2,3}; cout< ,vector >::comp(vecLeft,vecRight)< 程序输出结果:
standardclasstemplate
1
partitialspecialization
1
newpartitialspecialization
1
tovectorpartitialspecialization
13.模板类调用优先级
对主版本模板类、全特化类、偏特化类的调用优先级从高到低进行排序是:全特化类>偏特化类>主版本模板类。这样的优先级顺序对性能也是最好的。
但是模板特化并不只是为了性能优化,更多是为了让模板函数能够正常工作,最典型的例子就是STL中的iterator_traits。algorithm中大多数算法通过iterator对象来处理数据,但是同时允许以指针代替iterator对象,这是为了支持C-StyleArray。如果直接操作iterator,那么为了支持指针类型,每个算法函数都需要进行重载,因为指针没有::value_type类型。为了解决这个问题,STL使用了iterator_traits对iterator特性进行封装,并为指针类型做了偏特化处理,算法通过它来操作iterator,不需要知道实际操作的是iterator对象还是指针。
template
classiterator_traits
...
templateclassiterator_traits
...
templateclassiterator_traits
...后面两是针对指针类型的偏特化,也是偏特化的一种常见形式。
以上就是深入分析C++模板特化与偏特化的详细内容,更多关于C++模板特化与偏特化的资料请关注毛票票其它相关文章!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。