成员模板
普通(非模板)类的成员模板
我们设计一个类,包含一个重载的函数调用运算符,它接受一个指针并对此指针执行delete。与默认删除器不同,我们还在删除器被执行时打印一条信息。
class DebugDelet{
public:
DebugDelet(std::ostream &s =std::cerr):os(s){}
//与任何函数模板一样,T的类型有编译器推断
template <typename T>
void operator()(T *p) const
{os <<"deleting unique_ptr" << std::endl; delete p;}
private:
std::ostream os;
};
double *p = new double;
DebugDelete d; //可像delete表达式一样使用的对象
d(p); //调用DebugDelete::operator()(double*),释放p
int* ip = new int;
//在一个临时DebugDelete对象上调用operator()(int*)
DebugDelete()(ip);
//也可以将DebugDelete用作unique_ptr的删除器。
unique_ptr<int,DebugDelete> p(new int, DebugDelete());
这里传入unique_ptr的删除器还可以用函数,
void DebugDelete2(double *d){
cout << “Deleter called\n”;
delete d;
}
unique_ptr
类模板的成员模板
以Blob为例,我们为Blob类定义一个构造函数,它接受两个迭代器,表示要拷贝的元素的范围。
template<typename T>
class Blob{
template<typename It>
Blob(It b, It e);
};
在类的外部定义时,必须同时提供类模板和函数模板的模板参数列表。
template<typename T> //类模板的参数
template<typename It>
Blob<T>::Blob(It b,It e):data(std::make_shared<std::vector<T>>(b,e)){}
控制实例化
在大系统中,在多个文件中实例化相同模板的开销可能非常严重。在新标准中,我们可以通过显示实例化(explicit instantiation)来避免这种开销。
extern template declaration; //实例化声明
template declaration; //实例化定义
declaration是一个类或函数声明,其中所有模板参数已被替换为模板参数。例如,
//实例化声明与定义
extern template class Blob<string>; //声明
template int compare(const int&, const int&); //定义
extern声明就表示承诺会在程序其他位置有该实例化的一个非extern声明(定义)。
//Application.cc
//这些模板类型必须在程序的其他位置进行实例化
extern template class Blob<string>;
extern template int compare(const int&, const int&);
Blob<string> sa1,sa2; //实例化会出现在其他位置
//Blob<int>及其接受initializer_list的构造函数将在本文件中实例化
Blob<int> a1={1,2,3};
Blob<int> a2(a1); //拷贝构造函数在本文件中实例化
int i = compare(a1[0],a2[0]); //实例化出现在其他位置
//templateBuild.cc
//实例化文件必须为每个在其他文件中声明为extern的类型和函数提供一个(非extern)的定义
template int compare(const int&,const int&);
templalte class Blob<string>; //实例化模板的所有成员
实例化定义会实例化所有成员
与类模板成员函数的实例化不同(一个类模板的成员函数只有在使用到它时才进行实例化,这一特性使得即使某种类型不能完全符合模板操作的要求,我们依然能用该类型实例化类)。一个类模板的实例化定义会实例化所有成员。