函数模板特例化
之前的compare
不能处理字符指针,我们可以特例化一个处理字符指针的版本
template<typename T>
int compare(const T&, const T&);
template<>
int compare(const char* const& p1, const char* const& p2) {
return strcmp(p1, p2);
}
将T特例化为const char*
,原模板中的参数是指向T类型的const
引用,一个指针类型的const
版本是一个常量指针而不是指向const
类型的指针,所以我们需要将T特例化为指向const
的字符指针
特例化的本质是实例化一个模板,而非重载它,因此特例化不影响函数匹配
如果一个程序使用一个特例化版本,而同时原模板的一个实例具有相同的模板实参集合,我们本意是调用特例化版本,但因为特例化版本不在作用域中,所以就调用到了原模板的实例化版本,出现与预期不符的结果
模板及其特例化版本应该声明在同一个头文件中,所有同名模板的声明应该放在前面,然后是这些模板的特例化版本
类模板特例化
可以特例化一个hash
模板类的特例化版本,用来存储Sales_data
对象
namespace std
{ // 打开std命名空间,以便特例化std::hash
template<>
struct hash<Sales_data> {
typedef size_t result_type;
typedef Sales_data argument_type;
size_t operator()(const Sales_data& s) const;
};
size_t hash<Sales_data>::operator()(const Sales_data &s) const {
return hash<string>()(s.bookNo) ^
hash<unsigned>()(s.units_sold) ^
hash<double>()(s.revenue);
}
} // 关闭std命名空间,注意没有分号
需要声明为Sales_data
的友元
template<class T> class std::hash;
class Sales_data {
friend class std::hash<Sales_data>;
};
类模板部分特例化
类模板也可以特例化。与函数模板不同,类模板的特例化不必为所有模板参数提供实参,可以只指定一部分模板参数。一个类模板的部分特例化(partial specialization)版本本身还是一个模板,用户使用时必须为那些未指定的模板参数提供实参
只能部分特例化类模板,不能部分特例化函数模板。
由于类模板的部分特例化版本是一个模板,所以需要定义模板参数。对于每个未完全确定类型的模板参数,在特例化版本的模板参数列表中都有一项与之对应。在类名之后,需要为特例化的模板参数指定实参,这些实参位于模板名之后的尖括号中,与原始模板中的参数按位置相对应
// 通用版本
template <typename T>
struct remove_reference {
typedef T type;
};
// 部分特例化版本
template <typename T>
struct remove_reference<T &> { // 左值引用
typedef T type;
};
template <typename T>
struct remove_reference<T &&> { // 右值引用
typedef T type;
};
int i;
// decltype(42)为int,使用原始模板
remove_reference<decltype(42)>::type a;
// decltype(i)为int&,使用左值引用的部分特例化版本
remove_reference<decltype(i)>::type b;
// decltype(std::move(i))为int&&,使用右值引用的部分特例化版本
remove_reference<decltype(std::move(i))>::type c;
a
、b
和c
均为int
类型
特例化类的成员
可以只特例化类模板的指定成员函数,而不用特例化整个模板
template <typename T>
struct Foo {
Foo(const T& t = T()): mem(t) { }
void Bar() { /* ... */ }
T mem;
};
template<>
void Foo<int>::Bar() { // 特例化Foo<int>的成员Bar
// ...
}
Foo<string> fs; // 实例化Foo<string>::Foo()
fs.Bar(); // 实例化Foo<string>::Bar()
Foo<int> fi; // 实例化Foo<int>::Foo()
fi.Bar(); // 使用特例化版本的Foo<int>::Bar()