C++template 可以建立“类型安全”,还可以使得代码和其所处理对象类型彼此独立。
模板元编程: 在C++编译器内执行并于编译完成时停止执行。
条款41:了解隐式接口和编译期多态
面对对象编程中的显示接口和运行期多态(virtual 函数)比较重要,而 Template 和泛型编程中 隐式接口和编译器多态(template 具象化、函数重载)则更加重要。
隐式接口并不基于函数的签名式,由有效表达式组成。
template<typename T>
void doSomething(T& w){
if(w.size()>10 && w!= some){…}
}
上述隐式接口表示-类型T至少需要存在 成员函数size(),同时支持操作符 != 。
请记住:
1):class和template都支持接口和多态。
2):class的接口是显式的,以函数签名表示;多态是通过 virtual 函数发生于运行期。
3):template的接口是隐式的,基于有效表达式;多态由template具现化和函数重载解析发生于编译器。
条款42:了解 typename 的双重意义
从属名称: template 内出现的名称如果相依于某个 template 参数,称之为从属名称。
嵌套从属名称:如果从属名称在class内呈嵌套状。
template<typename C> // tempale 的关键字前缀
void print2nd(const C& container){
typename C::const_iterator* x;
// 标识为从属类型名称--指定C::const_iterator 为一种类型,否则的还也可能为某一变量。
…
}
请记住:
1):声明template时, 前缀关键字 class 和 typename 可互换。
2):使用关键词typename标识从属类型名称;但是不得在bass class list或者 成员处置列 中作为基类的修饰符。
条款43:学习处理模板化基类内的名称
模板类
template <typename T>
class send{…}
// 模板的全特化,及针对类型Companyz具象化
template <>
class send<Companyz>(){…}
模板化基类中可能存在特化具现的部分,因此其模板具现化出来的基类中可能存在不同的函数(特化部分)。在上述条件下,模板类继承中难以在基类中找寻基类,存在三种方式。
1:this-> 可以调用基类函数; —— this->sendClear();
2:使用 using 声明式声明基类函数;—— using send<Companyz>::sendClear;
3:明确指定调用函数的类别: —— send<Companyz>::sendClear();
请记住:
1):可在基类模板内通过 “this->”指涉基类内的成员名称,或者由一个明白写出的“基类资格修饰符”完成。
条款44:将与参数无关的代码抽离 template
请记住:
1):template生成多个class和多个函数,因此任何 template代码都不该与某个可能造成膨胀的template参数产生相依关系;
2):因非类型模板参数而造成的代码膨胀,可通过已函数参数或class成员变量替换tempalte参数来消除;
3):因参数类型而造成的代码膨胀,可以利用完全相同二级制表述的具现类型共享实现码。
条款45:运用成员函数模板接受所有兼容类型
template<typename T>
class smartPtr{
public:
template<typename U>
smartPtr(const smartPtr<U>& other);
}
上述代码中的构造函数表示可以根据 对像U 创建对象T。
请记住:
1):请使用成员函数模板生成“可接受所有兼容类型”的函数;
2):如果你声明的 成员模板 用于“泛化copy构造”或“泛化copy赋值操作“,还需要声明正常的copy构造函数和copy赋值操作函数。
条款46:需要转换类型时请为模板定义非成员函数
请记住:
1):当我们编写一个类模板,而它所提供的“于此template相关的”函数支持“所有参数的隐式类型转换”时,请将他定义为 类模板内部的friend函数。
条款47:请使用 traits class 表现类型信息
traits并不是关键字,而实预先定义好的构件,对于内置类型和用户定义的类型表现一样好。
类型的traits信息必须位于类型自身之外。
例如迭代器信息:
struct input_iterator_tag {}; // 输入迭代器
struct output_iterator_tag {}; // 输出迭代器
struct forward_iterator_tag: public input_iterator_tag {}; // 前向迭代器
struct bidirectional_iterator_tag: public forward_iterator_tag {}; // 双向迭代器
struct random_access_iterator_tag: public bidirectional_iterator_tag {}; // 随记迭代器
template<typename IterT> //
struct iterator_traits; // 迭代器分类相关
其运作方式为:针对每个类型 IterT,在struct iterato_traits<IterT>内,声明某个typdef 名为 iterator_category 作为类内的迭代器类型指代。
template<typename IterT, typename DistT>
void advance(TterT& iter, DisT d){
doadvance(iter, d, typename std::iterator_traits<IterT>::iterator_category()); // typename标识从属
// 第三个参数表示 IterT类中的 成员iterator_category,其为迭代器类型。
}
请记住:
1):trsits class使得 “类型信息”在编译器可用,通过template 及其特化实现。
2):整合重载技术后,trait class 有可能在编译器对类型执行 if…else 测试。
条款48:认识 template 元编程
typeid 用于在运行期获取变量类型。
模板元编程的优势:
1、确保度量单位正确(早期错误侦测);2、优化矩阵运算、3、生成客户定制的设计模式。
请记住:
1):模板元编程(TMP)可将工作由运行期移往编译器,可以获得更早期的进行错误侦测和更高的执行效率;
2):TMP可被用来生“基于政策选择组合”的客户定制代码,避免生成对某些特殊类型并不适合的代码。