类模板是用来生成类的蓝图的,与函数模板不同,编译器不能自动推断类模板的模板参数类型,所以在使用类模板时,需要使用尖括号来提供额外的信息(函数模板也可以使用尖括号来提供额外信息,语法正确,但是没有必要)。
vector<int> v1;
map<string, int> m1;
1. 定义类模板。类模板以关键字template开头,后跟模板参数列表
template <typename T>
class MyTemplate
{
public:
MyTymplate(const T& v);
...
};
2. 实例化类模板。使用一个类模板时,必须提供显示模板实参。
MyTemplate<int> myInstance;
对每一种指定的模板参数类型,编译器都会生成一个不同的类。类模板的每一个实例都会形成一个独立的类。
3. 在模板中引用模板类型。
template <typename T>
class MyTemplate
{
...
private:
std::shared_ptr<std::vector<T>> data; //在模板中引用模板类型
...
};
4. 类模板成员函数。类模板的成员函数既可以定义在类内部,也可以定义在类外部。类模板的每个实例都有自己版本的成员函数,具有和模板相同的模板参数,因此,定义在类外部的成员函数必须以关键字template开始,后接类模板参数列表。
template <typename T>
T& MyTemplate::foo(const T& t)
{
...
}
5. 类模板成员函数的实例化。如果一个成员函数没有被使用,则它不会被实例化。实例化时不需要提供模板实参。
MyTemplate<int> myInstance;
myInstance.foo(5);
6. 类模板和友元。一个类包含一个友元声明时,类与友元各自是否模板时相互无关的,它们之间的友元关系体现在各自实例之间的友元关系上,与普通的友元关系是一样的。
为了引用模板(类或者函数)的一个特定实例,我们首先必须声明模板本身。
//前置声明
template <typename> class BlobPtr;
template <typename> class Blob;
template <typename T> bool operator==(const Blot<T>&, const Blot<T>&);
tymplate <typename T>
class Blob
{
friend class BlobPtr<T>; //友元类
friend bool operator==<T>(const Blot<T>&, const Blot<T>&); //友元函数
};
7. 通用和特定的模板友好关系。一个类可以将一个类模板的每一个实例都声明为自己的友元,也可以限定特定的实例为自己的友元。
8. 类模板static成员。
template <typename T>
class Foo
{
public:
static std::size_t count(){return ctr;}
private:
static std::size_t ctr;
};
对任意给定类型X,都有一个Foo<X>::ctr和一个Foo<X>::count成员。所有的Foo<X>类型的对象共享相同的ctr对象和count函数。
Foo<int> f1,f2, f3; //共享相同的Foo<int>::ctr和一个Foo<int>::count成员
类模板静态成员的访问:
Foo<int> fi;
auto ct = Foo<int>::count(); //实例化Foo<int>::count
ct = fi.count(); //使用Foo<int>::count
ct = Foo::count();//错误:模板没有实例化