模板全特化

首先来看一个最初学习模板时的例子, 首先这是一个基础模板

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<>来标记这是一个全特化版本, 尖括号中应该是空的. 其次, 所有的模板参数都必须给定具体的类型, 不能使用typenameclass来表示. 当某个函数既有非特化版本又有全特化版本时, 编译器会优先调用全特化版本, 如上面的例子所示, 并且全特化版本和非特化版本的参数数量必须一致.

下面是一个类模板的全特化的例子

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的两个偏特化版本, 一个是固定Uint类型的版本, 另一个是双指针特化版本, 类型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;
};
本页内容