《C++ templates》读书笔记
整本书通过四个部分来介绍C++模板,基础,深入模板,模板与设计,高级应用程序这四个部分,从零开始到最为复杂的模板做法。
读书笔记
第一部分:基础
模板主要有函数模板,类模板这两个最重要的部分,其他的union类也可以上模板。
模板的语法,模板的关键词 template 后面使用 <>包围着模板参数,在遇到双重模板包含的时候,需要对连续的> 进行分隔,不然可能会对一些编译器不能分辨 > 和>>,造成混淆。
模板的使用的过程中,特别需要注意的是参数的传递和参数的转换,对于非引用型参数,在实参演绎的过程中,会出现数组到指针的类型转换(decay),基于这个属性,把std::string作为模板参数传递的时候需要注意。
一处定义原则:和全局变量和静态数据成员一样,非内联函数和成员函数只能被定义一次。
第二部分 深入模板
成员函数模板不能被声明为虚函数,因为虚函数调用机制的普遍实现用了一个虚函数表,每一个虚函数对应一个入口,但是成员函数的实例化个数需要等到整个程序翻译完毕才能否确定,这个和表的大小发生了冲突。但是类模板的普通成员函数可以是虚函数。
模板的链接:类模板不能和另外一个实体共享一个名称
模板参数:1,类型参数,通过typename或者class引入,两者等同。 2,非类型参数,在编译期间可以确定的值,整型或者枚举(如VectorN),指针类型(普通对象的指针,函数指针,指向成员的指针类型),引用类型(指向对象或者指向函数的引用,如Allocator) 3,模板的模板参数。是代表类模板的占位符(placeholder)
模板在1994年的时候,大多数编译器不能对函数模板进行重载,也没有名字空间,所以需要限制模板的扩展,Barton将运算符并作为类的普通友元参数定义在函数的外部,从而解决这个问题。
类模板能够被继承也可以继承,非依赖性基类(无需知道模板实参就可以完全确定类型的基类),如果在其的派生类中查找一个名称,会先在非依赖性基类中查找,然后才查找模板参数列表,优先级问题。
模板的实例化,只对需要的部分进行实例化,有些编译器会延迟模板的实例化。两阶段查找,第一阶段是模板的解析阶段,如查找非依赖性名称,查找结果也是不完整的。第二阶段是模板实例化阶段,发生在POI(源代码的实例化点),依赖性受限名称是在这个阶段查找。
因为模板在定义的时候有分离模型和包含模型,在涉及到编译的时候,名称的查找在两个阶段的表现不一。
模板的实参演绎只能用于函数模板和成员函数模板,不能用于类模板。S a(12) 是错误的,不能直接从构造函数 调用实参来演绎类模板参数T。
全局模板特化和由模板生成的实例化版本是不能够共存于同一个程序中的。
C++11中将POD分成两个基本概念的集合,平凡的(trival)和标准布局的(standard layout)的,只有满足这两个基本概念才能称为是POD类型。
一个trivial class或者struct应该符合以下定义:
拥有平凡的默认构造函数(trivial constructor)和析构函数(trivial destructor)
拥有平凡的复制构造函数(trivial copy constructor)和移动构造函数(trivial move constructor)
拥有平凡的复制赋值运算符(trivial assignment operator)和移动赋值运算符(trivial move operator)
不能包含虚拟函数和虚拟基类。
局部特化的一些重要约束
1,局部特化的实参必须和基本模板的相应参数在种类上是匹配的
2,局部特化的参数列表不能具有缺省值,但局部特化仍然可以使用基本类模板的缺省实参
3,局部特化的非类型实参只能是非类型值,或者是普遍的非类型模板参数
4,局部特化的模板实参列表不能和基本模板的参数列表完全相同
Metaprogramming是指借助于模板实例化机制,在编译阶段执行一些重要的计算。
第三部分: 模板与设计
模板的多态,实际对象是调用虚函数的指针所代表的对象。
动多态,是在运行期间绑定,
优点:能够优雅处理异类集合,可执行代码的大小通常较小,可以对代码进行完全编译
静多态,是在编译期间绑定
优点:可以很容易实现内建类型的集合,所生成的代码效率通常比较高,对于只提供部分接口的具体类型。
Trait和policy类,可以萃取类型,并且在编译器期间进行计算
trait表述了模板参数的一些自然的额外属性
policy表述了泛型函数和泛型类的一些可配置行为,通常都具有被经常使用的缺省值
空基类优化(empty base class optimization EBCO)技术,只要不会与同一类型的另一个对象或子对象分配在同一地址,就不需要为其分配任何空间。对其优化进行限制的根本原因是需要比较两个指针是否指向同一对象。
递归模板模式,一种通用的模式,派生类将本身作为模板参数传递给基类
简单应用:基类记录某个类的对象构造的总个数
Metaprogramming含有“对一个程序进行编程”的意思,目的是为了实现更多的功能。最大特点是某些用户自定义的计算可以在程序翻译期间进行。
模板实例化是一种基本的递归语言机制。
一个template metaprogram包含了
状态变量:也就是模板参数
迭代构造:通过递归
路径选择:通过使用条件表达式或者特化
整型算法:枚举里面的值应该为整型
C++标准只建议最多只进行17层的递归实例化。
表达式模板 (expression template)
表达式模板大大提高了数组操作的性能。
第四部分 高级应用
对于一些功能来说模板实现是最好的实现方法
类型区分:通过对类型的特化,来实现对类别的判断
组合类型(一些构造自其他类型的类型),简单的组合类型包括:普通类型,指针类型,引用类型和数组类型。常见的是类中,对类型的指针,或者是引用的特化
函数类型:参数的数量是任意的,常见于不定参数的使用在类上。
对于某个实体,这种能够在程序中获知它的高层次属性(诸如类型属性)的能力称为反射(reflection)
智能指针:封装了两个不同的所有权的属性(独占和共享)
资源获取即初始化(RAII模式)
内件指针可以用来完成以下的隐式转换:1,到void*类型的转换,2,到被指向的对象的一个基类指针的转换,3,到bool类型的转换(若指针为空则为false,否则true)
函数对象和回调
函数对象(仿函数)是指:可以使用函数调用语法进行调用的任何对象
总结
本书介绍了c++ template的各种入门语法和使用介绍,但是这本书有点多,适合粗泛阅读入门,入门之后选择更为详细和深入的书籍。