模板全特化
首先来看一个最初学习模板时的例子, 首先这是一个基础模板
template <typename T, typename U>
void print(T t, U u) {
std::cout << t << " " << u << std::endl;
}
模板全特化(Full Specialization)指的是为所有模板参数的某个特定组合提供一个特化版本, 例如
template <>
void print<int, double>(int a, double b) {
std::cout << "int: " << a << ", double: " << b << std::endl;
}
那么如果在主函数调用print(1, 2.0)
时, 将会调用特化版本的print
函数.
int main() {
print(1, 2.0);
print(1, 2);
}
// 会输出
// int: 1, double: 2.0
// 1 2
在模板全特化中需要注意的点是, 首先要用template<>
来标记这是一个全特化版本, 尖括号中应该是空的. 其次, 所有的模板参数都必须给定具体的类型, 不能使用typename
或class
来表示. 当某个函数既有非特化版本又有全特化版本时, 编译器会优先调用全特化版本, 如上面的例子所示, 并且全特化版本和非特化版本的参数数量必须一致.
下面是一个类模板的全特化的例子
template <typename T>
class Vector {
T *data;
public:
void print() {}
};
template <>
class Vector<bool> {
unsigned char *data;
public:
void print() { std::cout << "不要随意使用vector<bool>" << std::endl; }
}
模板偏特化
模板全特化中要求为所有的模板参数提供具体的类型, 那如果只为其中一部分模板参数提供具体的类型, 就是模板偏特化(Partial Specialization). 例如
template <typename T, typename U>
class MyClass {
public:
void print() {
std::cout << "T: " << typeid(T).name() << ", U: " << typeid(U).name() << std::endl;
}
}
template <typename T>
class MyClass<T, int> {
public:
void print() {
std::cout << "T: " << typeid(T).name() << ", U: int" << std::endl;
}
}
template <typename T>
class MyClass<T *, T *> {
public:
void print() {
std::cout << "T: " << typeid(T).name() << ", U: T*" << std::endl;
}
}
在这里提供了MyClass
的两个偏特化版本, 一个是固定U
为int
类型的版本, 另一个是双指针特化版本, 类型U
固定为T*
, 也就是T
的指针类型.
在C++中不允许函数的模板偏特化, 但可以通过函数重载来实现类似的效果. 例如
template <typename T, typename U>
void print(T t, U u) {
std::cout << "T: " << typeid(T).name() << ", U: " << typeid(U).name() << std::endl;
}
template <typename T>
void print(T t, int u) {
std::cout << "T: " << typeid(T).name() << ", U: int" << std::endl;
}
应用
模板偏特化主要用在元编程中. 比如实现类型特征萃取
template <typename T>
struct is_pointer : std::false_type {};
template <typename T>
struct is_pointer<T *> : std::true_type {};
再比如移除某个变量的const
修饰
template <typename T>
struct remove_const {
using type = T;
};
template <typename T>
struct remove_const<const T> {
using type = T;
};