1. template<class C>只是说C是一个类型名,它不必一定是某个类的名字。
2. 在类模版名字后随着由<>括起的一个类型名,也就成为(由这个模版所定义的)一个类的名字。
3. typedef在缩短由模版生成的长名字方面常常很有用处。另外,我们也经常希望不用去了解一个类型究竟是怎样定义的。typedef使我们可以隐藏起某个类型是由模版生成的这一事实。
typedef basic_string<char> string;
4. 模版类的成员本身也是模版参数化的,与它们所在的模版类的参数一样。在类外定义这些成员时,就必须显式的将它们定义为模版。
5. 模版能够直接支持通用型程序设计,即那种采用类型作为参数的程序设计。
6. 从一个模版类和一个模版参数生成一个类声明的过程通常被称为模版实例化。针对一个特定模版参数的模版版本称为是一个专门化。
7. 一个模版参数可以用于定义跟随其后的模版参数
template<class T, T def_val> char Cont{ /* */};
8. 模版参数可以是常量表达式,具有外部链接的对象或者函数的地址,或者非重载的指向成员的指针。用作模版参数的指针必须具有&of的形式,其中of是对象或者函数的名字;或者具有f的形式,f必须是一个函数名。到成员的指针必须具有&X::of的形式,这里的of是一个成员名。特别的,字符串文字量不能被接受为模版的参数。整数模版参数必须是常量。一个非类型的模版参数在模版的内部是一个常量,企图修改这种参数的值就是一个错误。(有几个不完全懂)
9. 在调用模版函数时,函数参数的类型决定到底应使用模版的那个版本,也就是说,模版的参数是有函数参数推断出来的
10. 绝不会对类模版的参数做任何推断
11. 如果不能从模版函数的参数推断出某个模版参数,我们就必须显式的去描述它。做这件事的方式与显式的为模版类提供参数类型参数一样:
template<class T> class vector {};
template<class T> T* create();
void f() {
vector<int> v;
int* p = create<int>();
}
显式描述的最常见用途是为模版函数提供返回值类型
12. 与默认的函数参数一样,在显式的模版参数表中,只有位于最后的类型可以不给出
13. 如果一个函数和一个专门化具有同样好的匹配,那么就选用函数。因为这个原因,对于sqrt(2.0)将选用sqrt(double)而不是sqrt<double>(double).
14. 可以通过显式限定来消解歧义
15. 用于描述策略的模版参数常常被称为特征(traits)
16. 通用模版必须在所有专门化之前声明
17. 说一个专门化比另一个更专门,如果能够与它匹配的每个实际参数表也能与另外的那个专门化匹配,但反过来就不对。
18. 从一个非模版类派生出一个模版类,这是为一组模版提供一个共同实现的一种方法。
template<class T> class Vector<T*> : private Vector<void*> {}
对这种示例还可以有另一种看法,这里用一个模版类为某种功能提供了一个优美而且类型安全的界面。
P309的例子没看太懂
19. 为了能有所区分,将虚函数提供的东西称作运行时多态性,而把模版提供的称为编译时多态性或者参数式多态性。
20. 一个类或者模版也可以包含本身就是模版的成员,例如
template<class Scalar> class Complex {
Scalar re, im;
public:
template<class T>
Complex(const complex<T>& c) : re(c.real()), im(c.imag()) {}
};
21. 成员模版不能是virtual
22. 为了使其他编译单位能够访问,就必须将这个模版定义显式的声明为export,方式是为了定义或者定义之前的某个声明上加上关键字export。