1. 类模板
template <类型参数表>
class 类模板名{
成员函数和成员变量
};
1.1 实例化类模板
实例化场所:
-当使用了类模板实例的名字,并且上下文环境要求存在类的定义时
-对象类型是一个类模板实例,当对象被定义时。此点被称作类的实例化点
-一个指针或引用指向一个类模板实例,当检查这个指针或引用所指的对象时
1.2 类模板的成员函数
在类模板外定义
template <类型参数表>
返回值类型 类模板名<类型参数名列表>::成员函数名(参数表)
{
...
}
1.3 类模板和友元
- 一对一
BlobPtr 和 Blob
BlobPtr 和 operator==
Blob 和 operator==
#include <iostream>
#include <sstream>
using namespace std;
template <typename T> class BlobPtr;
template <typename T> class Blob;
template <typename T>
bool operator==(const Blob<T> &, const BlobPtr<T>&);
template <typename T> class Blob
{
friend class BlobPtr<T>;
friend bool operator==<T>(const Blob<T>&, const BlobPtr<T>&);
private:
int a;
public:
Blob(T _a) :a(_a) {}
};
template <typename T> class BlobPtr {
friend bool operator==<T>(const Blob<T>&, const BlobPtr<T>&);
int a;
public:
BlobPtr(T _a) :a(_a) {}
};
template <typename T>
bool operator==(const Blob<T>& b, const BlobPtr<T>& bp)
{
return b.a == bp.a ? true : false;
}
int main()
{
Blob<int> b(1);
BlobPtr<int> bp(1);
std::cout << (b== bp) << endl;
}
template <typename T> class Pal;
class C
{
friend class Pal<C>; // C是所有是Pal<C>的友元
};
一对多:
template <typename T> class Pal;
class C
{
// Pal2 的所有实例都是C的友元,无需前置声明
template <typename T> friend class Pal2;
};
多对多
template <typename T>
class C2
{
// Pal2 的所有实例都是C2每个实例的友元,无需前置声明
template <typename T> friend class Pal2;
}
1.4 类模板的static成员
template <typename T>
class Foo {
public:
static std::size_t count() {
return ctr;
}
void addctr() {
ctr++;
}
void subctr() {
ctr--;
}
private:
static std::size_t ctr;
// 下面可以有其他成员接口
};
定义初始化
template <typename T>
std::size_t Foo<T>::ctr = 0; //定义并初始化 ctr
每个 Foo 的实例都有自己的 static 成员实例。即,对任意给定类型X,都有一个Foo<X>::ctr 和一个 Foo<X>::count() 成员函数。所有 Foo<X>类型的对象共享相同的 ctr 对象和 count 函数
类似任何其他成员函数,一个static成员函数只有在使用的时候才会被实例化.
1.5 使用类的类型成员
(使用typename 表示T为一个类型)
template <typename T>
typename T::value_type top(const T& c)
{
}
1.6 默认模板实参
类模板(从右到左的规则):
编译OK
template <typename T, typename T2 = int> class Pal; //编译OK
编译error (error C3747: 缺少默认 模板 参数: )
template <typename T =int, typename T= int> class Pal;
函数模板:
默认模板参数的位置则比较随意,但是推测的时候是从左往有的
// 没有函数匹配
template <typename T=int, typename U = int, typename U1 >
void f(T t = 0, U u = 0, U1 u1= 0) {};
f(1, 'c');
// 正常调用
template <typename T, typename U, typename U1=int >
void f(T t = 0, U u = 0, U1 u1= 0) {};
f(1, 'c');
1.7 成员模板
1.7.1 普通类的成员模板
class DebugDelete
{
public:
DebugDelete(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;
};
1.7.2 类模板的成员模板
template <typename T>
class Blob
{
template <typename It> Blob(It a, It b);
//...
};
//在类模板外部进行其成员模板的函数体定义时,需要同时为类模板和成员模板提供模板参数列表。
template <typename T>
template <typename It>
Blob<T>::Blob(It a, It b) : data(std::make_shared<vector<T>>(a, b)) { }