面向对象编程能处理再程序运行之前都未知的情况,而在泛型编程中,在编译时就能获知类型了。
C++中的容器、迭代器和算法都是泛型编程的例子;
模版是泛型编程的基础。
一个模板就是一个创建类或者函数的蓝图或者说公式。
16.1 定义模板
16.1.1 函数模板
我们可以定义一个通用的函数模板,而不是为每一个类型定义一个新函数,一个函数模板就是一个公式,可以用来针对特定类型的函数版本。
在模板参数列表<>里面可以使用逗号分隔多个参数;模板参数列表的作用好像函数参数列表。
编译器用推断出的模板参数来为我们实例化一个特定版本的函数;这些编译器生成的版本通常被称为模板的实例。
模板类型参数也可以被用来作为返回值类型。
类型参数前面必须使用关键字class或者typename;
模板中还可以定义非类型参数,一个非类型参数表示一个值,同样使用class或者typename来指定非类型参数。当一个模板被实例化时,非类型参数被一个用户提供的或者编译器推断出的值所代替,这些值必须是常量表达式。
一个非类型参数可以是一个整型或者是一个指向对象或者函数类型的指针或引用。绑定到非类型整型参数到实参必须是一个常量表达式。绑定到指针或者引用非类型的实参必须具有静态的生命期。
函数模板可以声明为inline或者constexpr
模板中的函数参数是const引用
模板函数中尽量减少对类型本身的条件
当编译器遇到一个模板定义时,它并不生成代码,只有当我们实例化模板的一个特定版本时,编译器才会生成代码。
与非模板代码不同,模板的头文件通常集包括声明也包括定义。
当使用模板时,所有不依赖模板参数的名字都必须是可见的,这是由模板的提供者来保证的。
用来实例化模板的所有参数、类型以及与类型关联的运算符的声明都必须是可见的,这是由模板的调用者来保证的。
编译器会在三个阶段报告错误:
- 编译模板本身时,检查语法错误,忘记分号或者变量名错误等;
- 编译器遇到模板使用时,对于函数模板,检查实参数目是否正确,对于类模板,检查是否提供正确数目的模板实参;
- 模板实例化时,报告类型相关的错误
保证传递给模板的实参支持模板所要求的操作,以及这些参数在模板中能正确工作是调用者的责任。