在介绍C++模板特化与偏特化之前,先简要回顾一下C++中的模板。
模板是泛型编程的基础,泛型编程即以一种独立于任何特定类型的方式编写代码。模板是创建泛型类或函数的公式。
类模板
类模板定义的一般形式如下所示:
//模板类
template <typename T>
class class_name {
···
}
其中,T为类模板所要使用的数据类型占位符名称,这个名称可以在类的定义中使用。
下面是类模板的实例。
#include <vector>
#include <iostream>
#include <stdexcept>
template<typename T>
class cQueue{
public:
void push(T const& elem) { q.push_back(elem); }
void pop() {
if (q.empty()) return;
q.pop_back();
}
T front(){
if(q.empty()) throw out_of_range("empty queue");
return q.front();
}
bool empty() const{ return q.empty();}
private:
std::vector<T> q;
};
函数模板
函数模板定义如下所示:
#include <cstdlib>
#include <cstdio>
template <typename T>
T Max(const &T t1, const &T t2 ) {
return t1 > t2 ? t1 : t2;
}
int main {
float a=1.2;
float b=2.0;
printf("the max is %f\n", Max(a,b));
return 0;
}
上面回顾了模板。可以看出,
如果是int/float/double类型的处理都是一样的处理,那么用上面介绍的模板类,或者模板函数就可以完美的解决。
如果增加对std::string类型或者char *的处理,且如果处理逻辑不一样呢,那是不是上面介绍的就不能解决了。
如果想把上面说的std::string问题解决,那就需要对std::string做特殊化处理,也就是特化。
特化分为全特化和偏特化
全特化
将所有的类型参数全部明确指定。
偏特化
将部分类型参数明确指
定。
#include <cstdio>
template<typename T1, typename T2>
class Test{
public:
Test(T1 x, T2 y):a(x),b(y){}
private:
T1 a;
T2 b;
}
template<> //全特化,所有的类型参数全部指定
class Test<int, char> {
Test(int x, char y):a(x),b(y){}
private:
int a;
char b;
}
template<typename T> //偏特化,部分类型参数指定
class Test<T, char> {
Test(T x, char y):a(x),b(y){}
private:
T a;
char b;
}
上述讲的都是类模板的特化,没有提及到函数模板的特化,是因为模板特化版本不参与函数的重载抉策过程,因此在和函数重载一起使用的时候,可能出现不符合预期的结果。因此标准C++禁止了函数模板的偏特化。
而在实际的开发过程中,经常遇到需要函数的特化场景。那怎么办了?
具体可以参考下面的文章,提出的几种解决方案,其中第一种解决方案应该是最容易被我们接受,也最容易被我们想到,通过类模板的特化,来实现函数模板的特化。