16.1.4 成员模板
一个类可以包含本身是模板的成员函数。这种成员被称为成员模板。成员模板不能是虚函数。
普通(非模板)类的成员模板
下面我们定义一个类,类似 unique_ptr 所使用的默认删除器类型。类似默认删除器,该类将包含一个重载的函数调用运算符,它接受一个指针并对此指针执行 delete。与默认删除器不同,我们的类还将在删除器被执行时打印一条信息。由于希望删除器适用于任何类型,所以我们将调用运算符定义为一个模板:
class DebugDelete {public:DebugDelete(std::ostream &s = std::cerr): os(s) { }template <typename T> void operator() (T *p) const { os << "deleting unique_ptr" << std::endl; delete p; }private:std::ostream &os;
};
与其它任何模板相同,成员模板也是以模板参数类型开始的。
每个 DebugDelete 对象都有一个 ostream 成员,用于写入数据;还包含一个自身是模板的成员函数。可以用这个类来代替 delete:
double *p = new double;
DebugDelete d; // 可以像 delete 表达式一样使用这个对象
d(p); // 和接口非常的像
int *ip = new int;
DebugDelete()(ip); // 在一个临时的 DebugDelete 对象上调用 operator()(int*)
类模板的成员模板
对于类模板,我们也可以为其定义成员模板。在这种情况下,类和成员各自有自己的、独立的模板参数。
例如,我们将为 Blob 类定义一个构造函数,它接受两个迭代器,表示要拷贝的元素范围:
template <typename T> class Blob {template <typename It> Blob(It b, It e);// ... ... ...
};
此构造函数有自己的模板类型参数 It,作为它的两个函数参数的类型。
与类模板的普通函数成员不同,成员模板是函数模板。当我们在类模板外定义一个成员模板时,必须同时为类模板和成员模板提供模板参数列表。类模板的参数列表在前,后跟成员自己的模板参数列表。
template<typename T>
template<typename It>
Blob<T>::Blob(It b, It e):data(std::make_shared<std::vector<T>>(b, e)) { }
实例化与成员模板
为了实例化一个类模板的成员模板,我们必须同时提供类和函数模板的实参。与往常一样,我们在哪个对象上调用成员模板,编译器就根据该对象的类型来推断模板参数的实参。与普通函数模板相同,编译器通常根据传递给成员模板的函数实参来推断它的模板实参:
int ia[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
vector<long> vi = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
list<const char*> w = {"now", "is", "the", "time"};
Blob<int> a1(begin(ia), end(ia)); // 实例化 Blob<int> 类的接受两个 int* 参数的构造函数
Blob<int> a2(vi.begin(), vi.end()); // 实例化 Blob<int> 类的接受两个 vector<long>::iterator 的构造函数
Blob<string> a3(w.begin(), w.end());// 实例化 Blob<string> 类的接受两个 list<const char*>::iterator 的构造函数
以 a1 为例,a1 的定义实例化了如下版本:
Blob<int>::Blob(int*, int*);