简介:
C++ templates 的最初发展动机很直接:让我们得以建立 “类型安全”(type-safe)的容器如 vector,list 和 map。然而当愈多人用上 templates,他们发现 templates 有能力完成愈多可能的变化。容器当然很好,但泛型编程(generic programing)——和 merge 就是这一类编程的成果。最终人们发现,C++ template 机制自身是一部完整的图灵机(Turing-complete):它可以被用来计算任何可计算的值。于是导出了模板元编程(template metaprograming),创造出 “在 C++ 编译器内执行并于编译完成时停止执行” 的程序。近来这些日子,容器反倒只成为 C++ template 馅饼上的一小部分。然而尽管 template 的应用如此宽广,有一组核心观念一直支撑着所有基于 template 的编程。那些观念便是本章焦点。
本章无法使你变成一个专家级的 template 程序员,但可以使你成为一个比较好的 template 程序员。本章也会给你必要信息,使你能够扩展你的 template 编程,到达你所渴望的境界。
条款41:了解隐式接口和编译器多态
classes 和 template 都支持接口(interfaces)和多态(polymorphism)。
对 classes 而言接口是显式的(explicit),以函数签名为中心。多态则是通过 virtual 函数发生于运行期。
对 template 参数而言,接口是隐式的(implicit),奠基于有效表达式。多态则是通过 template 具现化和函数重载解析(function overloading resolution)发生于编译器。
条款42:了解 typename 的双重意义
声明 template 参数时,前缀关键字 class 和 typename 可互换。
请使用关键字 typename 标识嵌套从属类型名称;但不得在 base class lists(基类列)或 member initialization list(成员初值列)内以它作为 base class 修饰符。
条款43:学习处理模板化基类内的名称
可在 derived class templates 内通过 “this->” 指涉 base class templates 内的成员名称,或藉由一个明白写出的 “base class 资格修饰符” 完成。
条款44:将与参数无关的代码抽离 templates
Templates 生成多个 classes 和多个函数,所以任何 template 代码都不该与某个造成膨胀的 template 参数产生相依关系。
因非类型模板参数(non-type template parameters)而造成的代码膨胀,往往可消除,做法是以函数参数或 class 成员变量替换 template 参数。
因类型参数(type parameters)而造成的代码膨胀,往往可降低,做法是让带有完全相同的二进制表述(binary representation)的具现类型(instantiation types)共享实现码。
条款45:运用成员函数模板接受所有兼容类型
请使用 member function templates(成员函数模板)生成 “可接受所有兼容类型” 的函数。
如果你声明 member templates 用于 “泛化 copy 构造” 或 “泛化 assignment 操作”,你还是需要声明正常的 copy 构造函数和 copy assignment 操作符。
条款46:需要类型转换时请为模板定义非成员函数
当我们编写一个 class template,而它所提供之 “与此 template 相关的” 函数支持 “所有参数之隐式类型转换” 时,请将那些函数定义为 “class template 内部的 friend 函数”。
条款47:请使用 traits classes 表现类型信息
Traits classes 使得 “类型相关信息” 在编译器可用。它们以 template 和 “templates 特化” 完成实现。
整合重载技术(overloading)后,traits classes 有可能在编译器对类型执行 if … else 测试。
条款48:认识 template 元编程
Template metaprograming(TMP,模板元编程)可将工作由运行期移往编译器,因而得以实现早起错误侦测和更高的执行效率。
TMP 可被用来生成 “基于政策选择组合”(based on combinations of policy choices)的客户定制代码,也可用来避免生成对某些特殊类型并不合适的代码。