模板特化
学习模板特化之前,我们先了解什么是特化,所谓特化就是将泛型的东西具体化。模板特化就是为已有的模板参数进行一些使其特殊化的指定,使得以前不受任何约束的模板参数,受到特定约束或完全被指定下来。
也许读者会想既然都确定下来了那定义模板还有何意义呢,很多时候我们既需要一个模板能应对各种情景,又需要它的某个特定的类型(比如bool)来进行特别的处理,这种情形下就需要对模板进行特化。模板特化可分为偏特化与全特化,本节我们就来学习一下这两种特化形式。
1、偏特化
偏特化就是模板中的模板参数没有被全部确定,需要编译器在编译时进行确定。例如定义一个类模板,如下所示:
template<typename T, typename U>
class A
{
//……
};
将其中一个模板形参特化为int类型,如下所示:
template<typename T>
class A<T, int>
{
//……
};
这就是偏特化的典型例子,一个参数被绑定到int类型,另一个参数由用户指定。
2、全特化
全特化就是模板中的模板参数全部被指定为确定的类型,其标志就是产生出完全确定的东西。例如有类模板定义,如下所示:
template<class T>
class Compare
{
public:
bool IsEqual(const T& lh, const T& rh)
{
return lh == rh;
}
};
将其特化为对float类型数据的比较,定义如下所示:
template<>
class Compare<float>
{
public:
bool IsEqual(const float& lh, const float& rh)
{
return abs(lh - rh) < 10e-3;
}
};
上述定义中template<>就是告诉编译器这是一个特化的模板,模板特化之后就可以处理特殊情况。
接下来我们通过一个案例来演示类模板与函数模板特化的使用,具体如例1所示。
例1
1 #include <iostream>
2 using namespace std;
3 //定义函数模板
4 template<typename T>
5 bool IsEqual(T t1, T t2)
6 {
7 return t1 == t2;
8 }
9 //函数模板的特化
10 template<>
11 bool IsEqual(char* s1, char* s2)
12 {
13 return strcmp(s1, s2) == 0;
14 }
15 //类模板
16 template<typename T>
17 class Compare
18 {
19 public:
20 bool IsEqual(T t1, T t2)
21 {
22 return t1 == t2;
23 }
24 };
25 //类模板特化
26 template<>
27 class Compare<char*>
28 {
29 public:
30 bool IsEqual(char* s1, char* s2)
31 {
32 return strcmp(s1, s2) == 0;
33 }
34 };
35 int main()
36 {
37 char str1[] = "abc";
38 char str2[] = "abc";
39 cout << "函数模板和函数模板特化" << endl;
40 cout << IsEqual(1, 3) << endl; //调用函数模板
41 cout << IsEqual(str1, str2) << endl; //调用特化的函数模板
42 Compare<int> c1;
43 Compare<char*> c2;
44 cout << "类模板和类模板特化" << endl;
45 cout << c1.IsEqual(1.2, 3.4) << endl; //调用类模板
46 cout << c2.IsEqual(str1, str2) << endl; //调用特化的类模板
47 system("pause");
48 return 0;
49 }
运行结果如图1所示。
图1 例1运行结果
例1中分别定义了相同功能的函数模板和类模板,然后将两种模板都特化为char类型,当用1、3变量调用时,都是调用的模板,当传入char类型的str1与str2时,都调用了特化了的模板。
在上述所讲的特化与偏特化中,都是将模板特化为绝对类型,除此之外,还可以将模板特化为引用、指针类型与模板类型,例如将例1中的类模板Compare特化为指针类型,代码如下所示:
template<typename T>
class Compare<T*>
{
public:
bool IsEqual(const T* pT1, const T* pT2)
{
return Compare<T>::IsEqual(*pT1, *pT2);
}
};
这种特化其实不是一种绝对的特化,它只是对类型做了某些限定,但仍然保留了其一定的模板性,这种特化给我们提供了极大的便利,如这里,我们无需对int、float等类型再分别做特化了。
还可以将其特化为另一个类模板,代码如下所示:
template<class T>
class Compare
{
public:
bool IsEqual(const vector<T>& lh, const vector<T>& rh)
{
if (lh.size() != rh.size())
return false;
else
{
for (int i = 0; i < lh.size(); ++i)
{
if (lh[i] != rh[i]) return false;
}
}
return true;
}
};
这就把IsEqual的参数限定为一种vector类型, 但具体是vector<int>还是vector<float>, 我们可以不关心, 因为对于这两种类型,我们的处理方式是一样的,把这种方式称为“半特化”。
关于模板,需要读者多加实践才能真正掌握其要领,体会到它给我们带来的极大方便,C++中的标准模板库就是基于模板来完成的,理解掌握好模板也能为学习STL打下坚实的基础。