Effective C++第三版之(七)Templates and Generic Programming

Templates and Generic Programming模板与泛型编程

条款41:Understand implicit interfaces and compile-time polymorphism.了解隐式接口和编绎期多态
1,classes与templates都支持接口和多态。
1)classes接口是显式的,由函数的签名式(函数名称、参数类型、返回类型)构成,多态通过virtual函数发生于运行期。
2)templates接口是隐式的,不基于函数签名式,由有效表达式组成,多态通过template实例化及函数重载解析,发生于编绎期。
2,面向对象编程多为显式接口(explicit interfaces)和运行期多态(runtime polymorphism),Templates及泛型编程,显式接口和运行期多态存在,但更多的是隐式接口和编绎期多态。
3,Templates中对类型T的调用即是T必须支持的隐式接口,Templates在编绎期实例化,类型T以不同的类型实例化即编绎期多态。

条款42:Understand the two meaning of typename.了解typename的双重意义
1,声明template类型参数时class与typename意义相同,依赖template参数T的名称为从属名称,从属名称嵌套在class内则为㠌套从属名称,但在template内声明㠌套或从属名称类型时存在歧义,名称类型如果与T内变量名称重复,编绎器缺省认为从属名称不是类型,需要在从属或嵌套名称前加上typaname告诉编绎器从属名称是个类型,或typedef typename从属或㠌套名称类型的别名。
2,typename须作为嵌套从属类型名称的前缀词,但template class的嵌套名称类型作为base class时,base class list和member initialization list(成员初始值列表)中出现的嵌套名称类型作为base class不需要typename声明。

条款43:Know how to access names in templatized base classes.模板化的基类名称访问
1,template derived class继承template base class,derived class内部调用base class的函数时,编绎器会提示函数不存在而无法通过编绎,因base class的template参数T未实例化,且base class的template有可能特例化后不存在一般template的接口,编绎器不进入base class作用域内查找,因此拒绝在template derived classes内访问继承自template base classes的成员。
2,解决此问题:
1)可在base class函数调用前加上this->。
2)使用using声明。
3)使用作用域运算符::明确函数在base class作用域内,但作用域运算符会关闭virtual绑定行为。
4)但当base class的template特例化后不存在此函数,derived class的template参数为base class特例化的参数时,编绎不通过。
3,当从Object Oriented C++到Template C++,继承并不完全一样。

条款44:Factor parameter-independent code out of templates.将与参数无关的代码抽离出templates
1,templates可节省时间避免代码重复,也可造成代码膨胀,源码看着简单整洁,目标码却重复臃肿。
2,定义class与另一class部分相同,将相同部分移到新class中,再使用继承或复合的方式令原有class获取这些共同特性,互异部分继续留在原class内,template同样如此,但template的重复比较隐晦。
3,class template的成员函数及function template使用时才实例化,实例化templates会生成多个classes和多个函数,template代码尽量不要与造成膨胀的template参数产生依赖关系。
1)类型参数造成的代码膨胀,可使用相同二进制表达的类型实现共享代码,例int, long具有相同的二进制表达,vector<int>和vector<long>的成员函数有可能完全相同,有些连接器会合并相同的函数实现码,有些不会.
2)在大多数平台上,所有指针类型都具有相同的二进制表达,template内操作强型指针T*时,令其调用无类型指针void*,由无类型指针完全实际工作,以此降低代码膨胀。
4,非类型模板参数实例化后是个编绎期常量,以函数参数或class成员变量替换,替换后可降低执行文件大小,避免代码膨胀,同时降低进程内存页大小,使程序执行更快速,但会增加对象大小。

条款45:Use member function templates to accept “all compatible types”.使用成员函数模板接受所有兼容类型
1,内置指针支持隐式类型转换,derived class指针可以隐式转换为base class指针,指向non-const对象的指针可转换为指向const对象的指针。
2,智能指针是行为像指针的对象,智能指针的模板参数类型转换稍微有点麻烦。
1)templates和泛型编程(Generic Programming)中具有base-derived关系的模板参数实例化同一个template后两个class并不具有base-derived关系。
2)智能指针的类型转换,可根据一个对象构造出另一个对象,但构造函数的数量是无止尽的,且template无限实例化,导致生成无限量构造函数,此时应该使用member function templates,称泛化(generalized)copy构造函数,泛化的copy构造函数不声明为explicit,参数可执行1中的隐式转换。
3)智能指针的类型转换通常是derived转换为base,需要限制base转换为derived,可在模板内部定义模板参数类型指针,在泛化的copy构造函数时以另一个对象的内置指针初始化本对象的内置指针,内置指针只支持derived转换为base,不支持base转换为derived,通过成员初始值列表完成限制。
3,member function templates还可支持赋值操作,例如shared_ptr支持兼容之内置指针、shared_ptr和weak_ptr的构造以及赋值行为。
4,声明member function templates生成可接受所有兼容类型的函数,用于泛化copy构造或泛化assignment操作,但编绎器依然会生成正常的non-template的构造函数和赋值运算符。

条款46:Define non-member functions inside templates when type conversions are desired.需要类型转换时,在模板内定义非成员函数
1,条款24中讨论过若所有参数需要类型转换,采用non-member函数。在template中,class template指定模板实参,function template模板参数由实参推断,实参推断时不考虑隐式类型转换,包括通过构造函数发生的隐式类型转换。
1)将function声明为template class内的friend函数,调用此函数时已由函数参数明确了模板参数,此时可使用隐式类型转换,并且可在template class内定义此friend函数。
2)传统friend函数的作用是访问class内non-public成员,template内friend函数是为了支持参数隐式类型转换的non-member函数自动实例化,定义于class内部自动成为inline,当函数较为复杂时,可在函数内部调用定义于class外部的辅助函数,减少inline声明带来的冲击。
2,部分编绎器强制将所有template定义式放在头文件中,此时template不一定是inline。

条款47:Use traits classes for information about types.使用traits classes表现类型信息
1,STL主要由容器、迭代器、算法的templates构成,STL有五种迭代器,每种迭代器支持的操作不同。
1)input迭代器只能单步向前移动,单次读取数据,istream_iterator便是这类迭代器。
2)output迭代器只能单步向前移动,单次写入数据,ostream_iterator便是这类迭代器。
3)forward迭代器只能单步向前移动,可多次读写数据,forward_list便是此迭代器。
4)bidirectional迭代器可双向移动,多次读写数据,list/map/set等都是此迭代器。
5)random access迭代器可随机访问任意位置,多次读写数据,vector/deque/string便是此迭代器。
2,iterator_traits要求自定义迭代器类型嵌套typedef声明iterator_category为以上五种类型之一,iterator_traits获取类型中的iterator_category,确认迭代器类型。
1)traits要求内置指针与迭代器表现一致,而内置类型无法嵌套类型信息,template可实现特例化版本。
2)迭代器iterator_traits针对内置指针实现特例化版本,内置指针类型为random access,支持内置指针的类型信息获取。
3,泛型算法中iterator_traits可在编绎期获取容器迭代器类型,识别不同的迭代器执行不同的操作,并重载算法,将迭代器类型作为模板参数分别重载,即可在编绎期确定执行的操作。

条款48:Be aware of template metaprogramming.认识template元编程
1,Template metaprogramming(TMP,模板元编程)是编写template-based C++程序并执行于编绎期的过程,将操作由运行期转移到编绎期,可将错误提前在编绎期找出来,并且程序更高效,较小的可执行文件、较短的运行期、较少的内存需求,但编绎时间变长。
2,条款47的TMP不同操作由template及其特例化实现,是汇编语言层的TMP。
1)TMP可将模板中的循环通过递归模板实例化实现,递归的结束则是模板的特例化,在递归过程中,需要确保所有度量单位的组合正确,即递归公式正确,只是此递归是递归模板。
2)此方法可优化矩阵运算,多个矩阵相乘需要保存两两相乘结果,TMP合并循环消除临时对象,使用较少的内存并且提升了执行速度。
3,TMP可基于组合(based on combinations of policy choices)将条款35中设计模式Strategy,Observer,Visitor等生成定制设计模式,templates表示独立的设计选项,再任意结合它们,实现定制的设计模式,例templates的智能指针行为,在编绎期间生成不同的智能指针类型。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值