1.模板特化的定义
C++中的模板特化不同于模板的实例化,模板参数在某种特定类型下的具体实现称为模板的特化。模板特化有时也称之为模板的具体化,分别有函数模板特化和类模板特化。
1.1函数模板特化
函数模板特化是在一个统一的函数模板不能在所有类型实例下正常工作时,需要定义类型参数在实例化为特定类型时函数模板的特定实现版本。查看如下例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
#include <iostream>
using
namespace
std;
template
<
typename
T> T Max(T t1,T t2){
return
(t1>t2)?t1:t2;
}
typedef
const
char
* CCP;
template
<> CCP Max<CCP>(CCP s1,CCP s2){
return
(
strcmp
(s1,s2)>0)?s1:s2;
}
int
main(){
//调用实例:int Max<int>(int,int)
int
i=Max(10,5);
//调用显示特化:const char* Max<const char*>(const char*,const char*)
const
char
* p=Max<
const
char
*>(
"very"
,
"good"
);
cout<<
"i:"
<<i<<endl;
cout<<
"p:"
<<p<<endl;
}
|
程序正常编译运行结果:
i:10
p:very
在函数模板显示特化定义(Explicit Specialization Definition)中,显示关键字template和一对尖括号<>,然后是函数模板特化的定义。该定义指出了模板名、被用来特化模板的模板实参,以及函数参数表和函数体。在上面的程序中,如果不给出函数模板Max<T>在T为const char*时的特化版本,那么在比较两个字符串的大小时,比较的是字符串的起始地址的大小,而不是字符串的内容在字典序中先后次序。
1.1.1使用函数重载替代函数模板特化
除了定义函数模板特化版本外,还可以直接给出模板函数在特定类型下的重载形式(普通函数)。使用函数重载可以实现函数模板特化的功能,也可以避免函数模板的特定实例的失效。例如,把上面的模板特化可以改成如下重载函数:
1
2
3
4
|
typedef
const
char
* CCP;
CCP Max(CCP s1,CCP s2){
return
(
strcmp
(s1,s2)>0)?s1:s2;
}
|
程序运行结果和使用函数模板特化相同。但是,使用普通函数重载和使用模板特化还是有不同之处,主要表现在如下两个方面:
(1)如果使用普通重载函数,那么不管是否发生实际的函数调用,都会在目标文件中生成该函数的二进制代码。而如果使用模板的特化版本,除非发生函数调用,否则不会在目标文件中包含特化模板函数的二进制代码。这符合函数模板的“惰性实例化”准则。
(2)如果使用普通重载函数,那么在分离编译模式下,应该在各个源文件中包含重载函数的申明,否则在某些原文件中就会使用模板实例化,而不是重载函数。
1.3类模板特化
类模板特化类似于函数模板的特化,即类模板参数在某种特定类型下的具体实现。考察如下代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
#include <iostream>
using
namespace
std;
template
<
typename
T>
class
A{
T num;
public
:
A(){
num=T(6.6);
}
void
print(){
cout<<
"A'num:"
<<num<<endl;
}
};
template
<>
class
A<
char
*>{
char
* str;
public
:
A(){
str=
"A' special definition "
;
}
void
print(){
cout<<str<<endl;
}
};
int
main(){
A<
int
> a1;
//显示模板实参的隐式实例化
a1.print();
A<
char
*> a2;
//使用特化的类模板
A2.print();
}
|
程序输出结果如下:
A'num:6
A' special definition
“I find that the harder i work,the more luck i seem to have!”