本书是C++模板编程的完全指南,旨在通过基本概念、常用技巧和应用实例3方面的有用资料,为读者打下C++模板知识的坚实基础。
全书共5个部分,22章。第1章全面介绍了本书的内容结构和相关情况。第1部分(第2~7章)以教程的风格介绍了模板的基本概念,第2部分(第8~13章)阐述了模板的语言细节,第3部分(第14~18章)介绍了C++模板所支持的基本设计技术,第4部分(第19~22章)深入探讨了各种使用模板的普通应用程序。附录部分是一处定义原则和重载解析的相关资料。
本书适合C++模板技术的初学者阅读,也可供有一定编程经验的C++程序员参考。
第1章 关于本书
1.1 阅读本书所需具备的知识
1.2 本书的整体结构
1.3 如何阅读本书
1.4 关于编程风格的一些说明
1.5 标准和现实
1.6 代码例子和更多的信息
1.7 反馈
第1部分 基础
第2章 函数模板
2.1 初探函数模板
2.1.1 定义模板
2.1.2 使用模板
2.2 实参的演绎(deduction)
2.3 模板参数
2.4 重载函数模板
2.5 小结
第3章 类模板
3.1 类模板Stack的实现
3.1.1 类模板的声明
3.1.2 成员函数的实现
3.2 类模板Stack的使用
3.3 类模板的特化
3.4 局部特化
3.5 缺省模板实参
3.6 小结
第4章 非类型模板参数
4.1 非类型的类模板参数
4.2 非类型的函数模板参数
4.3 非类型模板参数的限制
4.4 小结
第5章 技巧性的基础知识
5.1 关键字typename
5.2 使用this->
5.3 成员模板
5.4 模板的模板参数
5.5 零初始化
5.6 使用字符串作为函数模板的实参
5.7 小结
第6章 模板实战
6.1 包含模型
6.1.1 链接器错误
6.1.2 头文件中的模板
6.2 显式实例化
6.2.1 显式实例化的例子
6.2.2 整合包含模型和显式实例化
6.3 分离模型
6.3.1 关键字export
6.3.2 分离模型的限制
6.3.3 为分离模型做好准备
6.4 模板和内联
6.5 预编译头文件
6.6 调试模板
6.6.1 理解长段的错误信息
6.6.2 浅式实例化
6.6.3 长符号串
6.6.4 跟踪程序
6.6.5 Oracles
6.6.6 Archetypes(原型)
6.7 本章后记
6.8 小结
第7章 基本模板术语
7.1 “类模板”还是“模板类”
7.2 实例化和特化
7.3 声明和定义
7.4 一处定义原则
7.5 模板实参和模板参数
第2部分 深入模板
第8章 深入模板基础
8.1 参数化声明
8.1.1 虚成员函数
8.1.2 模板的链接
8.1.3 基本模板
8.2 模板参数
8.2.1 类型参数
8.2.2 非类型参数
8.2.3 模板的模板参数
8.2.4 缺省模板实参
8.3 模板实参
8.3.1 函数模板实参
8.3.2 类型实参
8.3.3 非类型实参
8.3.4 模板的模板实参
8.3.5 实参的等价性
8.4 友元
8.4.1 友元函数
8.4.2 友元模板
8.5 本章后记
第9章 模板中的名称
9.1 名称的分类
9.2 名称查找
9.2.1 Argument-Dependent Lookup(ADL)
9.2.2 友元名称插入
9.2.3 插入式类名称
9.3 解析模板
9.3.1 非模板中的上下文相关性
9.3.2 依赖型类型名称
9.3.3 依赖型模板名称
9.3.4 Using-Declarations中的依赖型名称
9.3.5 ADL和显式模板实参
9.4 派生和类模板
9.4.1 非依赖型基类
9.4.2 依赖型基类
9.5 本章后记
第10章 实例化
10.1 On-Demand实例化
10.2 延迟实例化
10.3 C++的实例化模型
10.3.1 两阶段查找
10.3.2 POI
10.3.3 包含模型与分离模型
10.3.4 跨翻译单元查找
10.3.5 例子
10.4 几种实现方案
10.4.1 贪婪实例化
10.4.2 询问实例化
10.4.3 迭代实例化
10.5 显式实例化
10.6 本章后记
第11章 模板实参演绎
11.1 演绎的过程
11.2 演绎的上下文
11.3 特殊的演绎情况
11.4 可接受的实参转型
11.5 类模板参数
11.6 缺省调用实参
11.7 Barton-Nackman方法
11.8 本章后记
第12章 特化与重载
12.1当泛型代码不再适用的时候
12.1.1透明自定义
12.1.2语义的透明性
12.2 重载函数模板
12.1.1 签名
12.2.2 重载的函数模板的局部排序
12.2.3 正式的排序原则
12.2.4 模板和非模板
12.3 显式特化
12.3.1 全局的类模板特化
12.3.2 全局的函数模板特化
12.3.3 全局成员特化
12.4 局部的类模板特化
12.5 本章后记
第13章 未来的方向
13.1 尖括号Hack
13.2 放松typename的原则
13.3 缺省函数模板实参
13.4 字符串文字和浮点型模板实参
13.5 放松模板的模板参数的匹配
13.6 typedef模板
13.7 函数模板的局部特化
13.8 typeof运算符
13.9 命名模板实参
13.10 静态属性
13.11 客户端的实例化诊断信息
13.12 重载类模板
13.13 List参数
13.14 布局控制
13.15 初始化器的演绎
13.16 函数表达式
13.17 本章后记
第3部分 模板与设计
第14章 模板的多态威力
14.1 动多态
14.2 静多态
14.3 动多态和静多态
14.3.1 术语
14.3.2 优点和缺点
14.3.3 将两种多态结合起来
14.4 新形式的设计模板
14.5 泛型程序设计
14.6 本章后记
第15章 Traits 与Policy类
15.1 一个实例:累加一个序列
15.1.1 Fixed Traits
15.1.2 Value Trait
15.1.3 参数化trait
15.1.4 Policy和Policy类
15.1.5 Trait和Policy:区别在何处?
15.1.6 成员模板 和 模板的模板参数
15.1.7 组合多个Policies 和/或 Traits
15.1.8 运用普通的迭代器进行累积
15.2 类型函数
15.2.1 确定元素的类型
15.2.2 确定class类型
15.2.3 引用和限定符
15.2.4 Promotion trait
15.3 Policy Traits
15.3.1 只读的参数类型
15.3.2 拷贝、交换和移动
15.4 本章后记
第16章 模板与继承
16.1 命名模板参数
16.2 空基类优化
16.3.1 布局原则
16.2.2 成员作基类
16.3 奇特的递归模板模式
16.4 参数化虚拟性
16.5 本章后记
第17章 Metaprograms
17.1 Metaprogram的第一个实例
17.2 枚举值 和 静态常量
17.3 第2个例子:计算平方根
17.4 使用演绎变量
17.5 计算完整性
17.6 递归实例化 和 递归模板实参
17.7 使用Metaprograms来展开循环
17.8 本章后记
第18章 表达式模板
18.1 临时变量和分割循环
18.2 在模板实参中编码表达式
18.2.1 表达式模板的操作数
18.2.2 数组类型
18.2.3 运算符
18.2.4 回顾
18.2.5 表达式模板赋值
18.3 表达式模板的性能与约束
18.4 本章后记
第4部分 高级应用程序
第19章 类型区分
19.1 辨别基本类型
19.2 辨别组合类型
19.3 辨别函数类型
19.4 运用重载解析辨别枚举类型
19.5 辨别class类型
19.6 装配成一个辨别所有类型的函数模板
19.7 本章后记
第20章. 智能指针
20.1 Holders and Trules
20.1.1 安全处理异常
20.1.2 Holders
20.1.3 作为成员的Holders
20.1.4 资源获取于初始化
20.1.5 Holder的局限
20.1.6 复制Holders
20.1.7 跨函数调用地复制Holder
20.1.8 Trules
20.2 引用记数
20.2.1 计数器在什么地方
20.2.2 并发访问计数器
20.2.3 析构和释放
20.2.4 CountingPtr 模板
20.2.5 一个简单的非侵入式计数器
20.2.6 一个简单的侵入式计数器模板
20.2.7 常数性
20.2.8 隐式转型
20.2.9 比较
20.3 本章后记
第21章 Tuples
21.1 Duos
21.2 可递归Duo
21.2.1 域的个数
21.2.2 域的类型
21.2.3 域的值
21.3 Tuple构造
21.4 本章后记
第22章 函数对象和回调
22.1 直接调用、间接调用与内联调用
22.2 函数指针与函数引用
22.3 成员函数指针
22.4 class类型的仿函数
22.4.1 class类型仿函数的第1个实例
22.4.2 class类型仿函数的类型
22.5 指定仿函数
22.5.1 作为模板类型实参的仿函数
22.5.2 作为函数调用实参的仿函数
22.5.3 结合函数调用参数和模板类型参数
22.5.4 作为非类型模板实参的仿函数
22.5.5 函数指针的封装
22.6 内省
22.6.1 分析一个仿函数的类型
22.6.2 访问参数的类型
22.6.3 封装函数指针
22.7 函数对象组合
22.7.1 简单的组合
22.7.2 混合类型的组合
22.7.3 减少参数的个数
22.8 值绑定
22.8.1 选择绑定的目标
22.8.2 绑定签名
22.8.3 实参选择
22.8.4 辅助函数
22.9 仿函数操作:一个完整的实现
22.10 本章后记
附录A 一处定义原则
A.1 翻译单元
A.2 声明和定义
A.3 一处定义原则的细节
A.3.1 程序的一处定义约束
A.3.2 翻译单元的一处定义约束
A.3.3 跨翻译单元的等价性约束
附录B 重载解析
B.1 何时应用重载解析
B.2 简化过的重载解析
B.2.1 成员函数的隐含实参
B.2.2 细化完美匹配
B.3重载的细节
B.3.1 非模板优先
B.3.2 转型序列
B.3.3 指针的转型
B.3.4 仿函数和代理函数
B.3.5 其它的重载情况
参考资料
术语表
译者序
C++真可谓是包罗万象、博大精深。每个在C++中沉迷多年的爱好者都难免会有这样的感慨:使用C++多年过后,我们往往只能算是一个熟练的使用者,却从来不敢给自己冠上“精通C++”的头衔。难道“精通C++”永远都是不惭的大言?然而,在学习、使用和研究C++的过程中,我们总是期望能够向“精通”不断迈进,并领悟C++语言的精髓。我想,要做到这一点起码要注意3个方面:一要把握语言发展的脉搏,二要多应用标准技术,三要洞悉标准技术背后的实现细节。做到这些往往能够事半功倍。
近年来,C++的新发展主要是在GP(泛型程序设计)方面大放异彩:标准库、boost库、容器、迭代子、仿函数等都是围绕着GP不断呈现出来的,它们代表了现今C++程序设计的特性。而在这种种技术的背后,隐含着一种根深蒂固的共性:模板技术,处处都是模板代码。我们可以说:泛型程序设计本身就是基于模板的程序设计。也正是模板的这种编译期机制,进一步地展现了GP的优越,体现C++高效率的特点,更有助于GP达到与OO并驾齐驱的地位。
使用了多年标准库等技术之后,每个人都曾经编写过许许多多模板代码,但在每天的重复劳动之余,很多人却未能真正洞悉隐藏在模板背后的实现细节。诸如特化、局部特化、实例化、重载解析等编译器实现机理,相信真正了解的人并不多。这使得我们始终未能真正摆脱我们所使用的特性的束缚,也就无法实现更加符合具体应用的技术与特性。在这种情况下,用起这些特性来总会觉得心里不踏实。这未免是程序员的一种悲哀。
从前面列出的3个方面上看,本书都能够解决读者的疑惑。本书前半部分内容为读者释疑解惑,后半部分内容则更加贴近开发者,使所探讨的技术真正发挥其效能;因而,也总能带给人豁然开朗的感觉,并使你深深体会到作者选材的独到之处。关于本书内容的全面介绍,请参考第1章,我在此就不再赘述了。
C++编程的书籍,现如今已是淋漓满目、硕果累累。但是对于C++和模板这个至关重要的领域,即使在未来很长一段时间里,本书也必定有着不可替代的地位,这一点从亚马逊的5星级公评和一直位于前列的销售排名可见一斑。
对于本书的翻译,我力求做到语言平实无华,期望能以流畅的语句带给读者一个轻松的阅读过程。在近一年的翻译过程中,我一次又一次地拖延了出版社的计划,正是为了真正尽到一个译者的职责,对技术和文字把好关。但“丑媳妇总要见公婆”,这本书也终究还是要和读者见面,所以我的修润也只能告以段落。在阅读的过程中,如果您有中肯的批评意见,我一定虚心地接收。我也希望能够就此书的内容与读者有更多地交流。我的电子邮箱是dotcom@263.net。
致谢
首先,我要感谢本书的编辑陈冀康。对我每次提交的电子稿件,他都仔细研读,并与我细细讨论书中的每个细节。与他合作是一次令人愉快的经历。
我要感谢我的恩师北京理工大学的陈英老师,感谢陈老师的宽容与培养。袁卫东是本书前半部分的第1位读者,他花了很多时间,为我指出了许多不足之处。王曦(虫虫)是第16章的初稿译者,他的译文准确生动,给我带来很多宝贵的启发。另外,孟岩和熊节两位好友对C++有着多年的学习经历和丰富的知识背景,他们在我不断学习探索的过程中,给予我极大的帮助。
再一次,我要感谢在深圳的许多好友的支持。最后,感谢我的亲人和我的女友;在我工作的时候,每次都是你们在我身边;在我收获的时候,我最先想到的人总是你。
陈伟柱
2003年11月
David Vandevoorde 有20多年的C++工作经验,C++标准委员会成员。曾因为审校The C++ Programming Language一书的草稿,获得Bjarne Stroustrup的推荐,编写了C++ Solutions。
Nicolai M. Josuttis The C++ Standard Library - A Tutorial and Reference(中文版名为《C++标准库》)的作者,这本书出版以后成为实际上的标准读本。
陈伟柱 北京理工大学计算机专业研究生,C++编程技术爱好者,技术功底扎实,翻译准确平实,其译作《C++代码设计与重用》获得读者好评。
在C++中,模板(Template)这个概念已经存在十几年了;1990年出版的Annotated C++ Reference Manual(即“ARM”,见[EllisStroustrupARM])就已经介绍了模板的一些内容;实际上,在这之前的许多专业文档也已经对模板进行了一些描述。然而,即使过了十几年之后,对于模板这一吸引人的、复杂的、强有力的C++特性,仍然没有一本著作能够集中阐述它的基本概念和高级技术。我们觉得有必要阐述这些令人费解的地方,于是就决定编写这本关于模板的书籍(这些说法或许会显得稍微缺乏谦虚)。
然而,我们两人有着不同的背景;对于这项任务,也有着不同的目的。David是一个很有经验的编译器实现者,同时也是C++标准委员会核心语言工作组的成员。他的目的在于:详细而且准确地描述模板的功能(和问题)。Nico是一个“普通”的(应用程序)程序员,同时也是C++标准委员会程序库工作小组的成员。他的目的在于:让读者理解他所使用的各种模板技术和使用过程中的收获。另外,我们期望可以与你(读者)和整个(C++)社团共享这些知识,让我们都避免对模板的更多误解、疑惑和忧虑。
于是,你在书中既会看到带有例子的概念性介绍,也会看到模板具体行为的详细描述。我们将从模板的基本概念开始介绍,逐步过渡到“模板程序设计的艺术”,其中你将会发现(或者再次发现)诸如静态多态、policy类、metaprogramming、表达式模板等技术。另外,基于标准库中几乎到处都涉及到模板,在此你还可以加深对标准库的理解。
在本书的编写过程中,我们学会了很多知识,也获得了不少的乐趣。我们希望你在阅读的过程中也能有这样的感受,享受这本书和这份乐趣!