了解隐式接口与编译期多态

  1. 面向对象世界编程总是以显式接口和运行期多态解决问题,显式接口在源码中明确可见,虚函数则实现所谓的运行期多态
  2. 模板及泛型编程中隐式接口及编译期多态则更为重要,模板中的对象表达式是模板参数必须支持的一组隐式接口,而以不同的template参数具现化函数模板会导致调用不同的函数,这就是所谓的编译期多态。
  3. classes和templates都支持接口和多态
  4. 对classes而言接口是显式的,以函数签名为中心,多态则是通过virtual函数发生于运行期
  5. 对template参数而言,接口是隐式的,奠基于有效表达式。多态则是通过template具现化和函数重载解析发生于编译期。

了解typename的双重意义

  1. 从C++的角度看,声明template参数时,不论使用关键字class或typename,意义完全相同
  2. template内出现的名称如果相依于某个template参数,称之为从属名称,如果从属名称在class内呈嵌套状,我们称它为嵌套从属名称。
  3. 如果解析器在template中遭遇一个嵌套从属名称,它便假设这名称不是个类型,除非我们告诉它是。所以缺省情况下嵌套从属名称不是类型。
  4. 如果我们想要说明一个嵌套从属名称是一个类型,我们只要在紧邻它之前放置关键字typename即可。任何时候当我们想要在template中指涉一个嵌套从属类型名称,就必须在紧邻它的前一个位置放上关键字typename。
  5. typename只被用来验明嵌套从属类型名称,其他名称不该有它的存在。
  6. typename不能出现在基类列表内的嵌套从属类型名称之前,也不能出现在成员初始化列表中作为基类修饰符。
  7. typedef嵌套从属类型名称时需要在typedef后面加上typename

学习处理模板化基类内的名称

  1. 当编译器遭遇类继承自一个类模板时,编译器并不知道这个类继承自什么样的class,因为不到模板具现化时无法确定这个class是什么,因此也就无法得知它是否有某个成员函数
  2. 由于基类模板很有可能被特化,而特化版本可能不提供和一般性template相同的接口,因此编译器往往拒绝在模板化基类中寻找继承而来的名称
  3. 解决上述问题的三个解决办法分别是在基类函数调用动作之前加上this->,使用using声明式和使用::明确指出被调用的函数位于基类中,不过明确指出函数位于基类内造成的一大问题是如果被调用的是virtual函数,会造成虚函数无法进行动态绑定。

将与参数无关的代码抽离templates

  1. 使用模板会使源码看起来简洁,但是如果我们不小心的话,使用模板可能会导致代码膨胀:其二进制码带着重复(或几乎重复)的代码、数据或两者。
  2. 模板生成多个classes和多个函数,所以任何模板代码都不该与某个造成膨胀的template参数产生相依关系
  3. 因非类型模板参数而造成的的代码膨胀,往往可以消除,做法是以函数参数或class成员变量替换模板参数
  4. 因类型参数而造成的代码膨胀,往往可降低,做法是让带有完全相同二进制表述的具现类型共享实现码

运用成员函数模板接受所有兼容类型

  1. 我们可以将成员函数模板运用在构造函数上和赋值操作符上,能使得类模板拥有泛化的copy构造函数和赋值操作符。
  2. 我们可以使用一些隐式接口要求来约束哪些类型可以用于成员函数模板。
  3. 成员函数模板并不改变语言规则,在class内部声明泛化拷贝构造函数并不会阻止编译器生成它们自己的拷贝构造函数,相同规则也用于赋值操作符,因此如果我们想要控制拷贝构造的方方面面必须同时声明泛化拷贝构造函数和“正常”拷贝构造函数
  4. 我们可以使用成员函数模板生成“可接受所有兼容类型”的函数。

需要类型转换时请将模板定义非成员函数

  1. template实参推导过程中从不将隐式转换函数纳入考虑
  2. 为了缓和编译器在模板实参推导方面受到的挑战,模板类中的friend声明可以指涉某个特定函数,而类模板并不依赖模板实参推导(只有函数模板依赖)。
  3. 当类模板具现出时,作为friend函数也被具现出来了呢,此时编译器调用它时可以使用隐式转换函数,但由于friend函数声明不在类中因此会出现连接错误
  4. 为了解决连接错误,我们需要在类中定义这个friend函数,并且隐式成为了内联函数。
  5. 当我们编写一个类模板,而它所提供之“与此模板相关的”函数支持“所有参数之隐式类型转换”时,请将那些函数定义为“类模板内部的friend函数”。

请使用traits classes表现类型信息

  1. Traits templates使得“类型相关信息”在编译期可用。它们以templates和“templates特化”完成实现
  2. 整合重载技术后,traits classes有可能在编译期对类型执行if…else测试

认识template元编程

  1. 编译器必须确保所有源码都有效,纵使是不会执行起来的代码,否则可能会导致编译期问题
  2. TMP没有真正的循环构件,所以循环效果藉由递归完成,TMP循环并不涉及递归函数调用,而是涉及“递归模板具现化”
  3. TMP可将工作由运行期移往编译期,因而得以实现早期侦查错误和更高的执行效率
  4. TMP可被用来生成“基于政策选择组合”的客户定制代码,也可用来避免生成对某些特殊类型并不适合的代码