新書推薦:
《
伦理学与生活(第11版)
》
售價:HK$
118.8
《
巴格达新版 和平之城 血腥之城 汗青堂丛书055
》
售價:HK$
118.8
《
水之契约
》
售價:HK$
79.2
《
ABB工业机器人离线编程与仿真
》
售價:HK$
130.9
《
工厂生产计划精细化、精益化、精进化管理手册
》
售價:HK$
75.9
《
中国画技法与教学研究
》
售價:HK$
72.6
《
生命瞬间 人生风采——晚晴居影集
》
售價:HK$
107.8
《
西方毛发时尚演变
》
售價:HK$
107.8
編輯推薦:
吴咏炜、祁宇、张银奎联袂推荐!
通过C 20模板元编程,将编译期计算转化为高性能代码引擎,让复杂泛型设计变得简单可维护。
解决模板“难读、难写、难调试”三大痛点。
內容簡介:
学习元编程技术如何创建数据结构和函数,从而在编译时进行计算。通过《C 20模板元编程》,你将理解模板如何帮助你避免编写重复代码,模板是创建通用库(如标准库或Boost)的关键,这些库可以在多种程序中使用。
來源:香港大書城megBookStore,http://www.megbook.com.hk 本书的前几章将为你提供关于模板和元编程基础的知识。然后,你将开始练习编写复杂的模板,并探索高级概念,如模板递归、模板实参推导、转发引用、类型特征和条件编译。在此过程中,你将学习如何编写变参模板,以及如何使用C 20的约束和概念为模板实参提供约束和限制。最后,你将应用C 元编程模板的知识实现各种元编程模式和技术。
到本书结束时,你将学会如何编写有效的模板,并在日常编程中使用元编程。
● 理解所有类型模板的语法
● 学习特化和实例化的工作原理
● 掌握模板实参推导和转发引用
● 轻松编写变参模板
● 掌握类型特征和条件编译
● 使用 C 20 的约束和概念限制模板实参
● 实现CRTP、混入(mixin)和标签派发等模式
關於作者:
马里乌斯·班西拉(Marius Bancila)于2002年作为一名软件开发人员开始了职业生涯,专注于使用 Visual C 、C# 和 .NET 框架开发桌面应用程序。尽管多年来使用过许多编程和脚本语言(例如 Pascal、C、C 、Java、JavaScript、C#、VB.NET、MC 、C /CLI、HTML、CSS 等),但 C 始终是他的首选语言。目前他在挪威的Visma公司担任 ERP 系统的系统架构师。
Marius Bancila是Modern C Programming Cookbook和Modern C Challenge等多本C 技术图书的作者,热衷于与他人分享技术专长,并因此自2006年起连续18年被授予微软MVP(最有价值专家)称号。他撰写了大量技术文章,创建和参与了多个开源项目,并活跃于各类在线开发者社区。
目錄 :
第Ⅰ部分 模板的核心概念
第1章 模板的简介 3
1.1 理解模板的必要性 3
1.2 编写你的第一个模板 6
1.3 理解模板术语 9
1.4 模板的简史 10
1.5 模板的优缺点 12
1.6 总结 12
1.7 问题 13
第2章 模板的基础 15
2.1 定义函数模板 15
2.2 定义类模板 18
2.3 定义成员函数模板 20
2.4 理解模板形参 21
2.4.1 类型模板形参 22
2.4.2 非类型模板形参 23
2.4.3 模板模板形参 28
2.4.4 默认模板实参 30
2.5 理解模板实例化 32
2.5.1 隐式实例化 32
2.5.2 显式实例化 35
2.6 理解模板特化 39
2.6.1 显式特化 39
2.6.2 部分特化 43
2.7 定义变量模板 46
2.8 定义别名模板 49
2.9 探索泛型lambda和lambda模板 51
2.10 总结 57
2.11 问题 57
第3章 变参模板 59
3.1 理解变参模板的必要性 59
3.2 变参函数模板 61
3.3 形参包 65
3.4 变参类模板 73
3.5 折叠表达式 79
3.6 变参别名模板 82
3.7 变参变量模板 84
3.8 总结 84
3.9 问题 85
第Ⅱ部分 高级模板特性
第4章 高级模板的概念 89
4. 1 理解名称绑定和依赖名称 89
4.1.1 两阶段名称查找 91
4.1.2 依赖类型名称 94
4.1.3 依赖模板名称 96
4.1.4 当前实例化 97
4.2 探索模板递归 99
4.3 函数模板实参推导 103
4.4 类模板实参推导 112
4.5 转发引用 117
4.6 decltype说明符 123
4.7 std::declval类型运算符 128
4.8 理解模板中的友元关系 130
4.9 总结 135
4.10 问题 135
第5章 类型特征和条件编译 137
5.1 理解和定义类型特征 137
5.2 探索SFINAE及其目的 141
5.3 使用enable_if类型特征启用SFINAE 145
5.4 使用 constexpr if 149
5.5 探索标准库类型特征 152
5.5.1 查询类型类别 152
5.5.2 查询类型属性 155
5.5.3 查询支持的操作 157
5.5.4 查询类型之间的关系 158
5.5.5 修改const/volatile说明符、引用、指针或符号 159
5.5.6 各种转换 160
5.6 使用类型特征的实际例子 163
5.6.1 实现拷贝算法 163
5.6.2 构建同质的变参函数模板 166
5.7 总结 167
5.8 问题 168
第6章 概念和约束 169
6.1 理解概念的必要性 169
6.2 定义概念 174
6.3 探索requires表达式 176
6.3.1 简单要求 177
6.3.2 类型要求 179
6.3.3 复合要求 180
6.3.4 嵌套要求 182
6.4 组合约束 183
6.5 了解带约束模板的顺序 187
6.6 约束非模板成员函数 190
6.7 约束类模板 193
6.8 约束变量模板和模板别名 194
6.9 学习更多指定约束的方法 195
6.10 使用概念约束auto形参 196
6.11 探索标准概念库 198
6.12 总结 202
6.13 问题 202
第Ⅲ部分 模板的应用
第7章 模式和惯用法 205
7.1 动态多态和静态多态 205
7.2 奇异递归模板模式 208
7.2.1 使用CRTP限制对象实例化的次数 210
7.2.2 使用CRTP添加功能 211
7.2.3 实现组合设计模式 213
7.2.4 标准库中的CRTP 217
7.3 混入 220
7.4 类型擦除 225
7.5 标签派发 231
7.6 表达式模板 236
7.7 类型列表 243
7.7.1 使用类型列表 245
7.7.2 实现对类型列表的操作 247
7.8 总结 253
7.9 问题 254
第8章 范围和算法 255
8.1 理解容器、迭代器和算法的设计 255
8.2 创建自定义容器和迭代器 262
8.2.1 实现环形区缓冲容器 263
8.2.2 为环形缓冲区容器实现迭代器类型 269
8.3 编写自定义通用算法 275
8.4 总结 277
8.5 问题 278
第9章 范围库 279
9.1 从抽象范围到范围库 279
9.2 理解范围概念和视图 281
9.3 理解受约束算法 291
9.4 编写自己的范围适配器 294
9.5 总结 300
9.6 问题 300
附录A 结束语 301
——以下内容可扫描封底二维码下载——
问题答案 303
参考文献 313
內容試閱 :
玄之又玄,众妙之门
大家都知道,AI可以写代码了。你用过吗?感觉如何?
前不久,我在准备GPU训练营的试验程序时,确实用AI写了一些代码,既有传统的CPU端代码,也有更现代的GPU端代码。我用AI写代码的目的有两个,一是提高工作效率,二是亲身测试AI写代码的能力。
亲身测试一番之后,我有两个比较强烈的感受。第一个感受是对于比较简单的任务,AI确实可以写出质量不错的代码,不仅速度快,而且准确度很高,没有误拼等人类常犯的低级错误。第二个感受是,随着代码量的上升,AI写的代码也开始具有人类代码常有的问题,先是重复,啰嗦,然后是有bug(错误)。
众所周知,AI领域吸引了大量的投资和优秀的人才,新的成果不断涌现。因此,我们比较难预测AI的代码能力在2年后会怎么样?在5年和10年后又会怎么样?
AI技术的发展速度难以预测,但是我觉得以下三个趋势是比较确定的。首先,AI技术确实会改变软件产业的格局,一些简单的软件开发任务将AI化,因为使用AI技术能大大提高编码的效率,不再需要那么多的程序员来写代码。第二,随着AI技术不断被应用到软件开发领域,软件的产量和软件的代码量都将随之上升。而且,AI产生的代码也是不完美并且存在瑕疵的。软件团队里将需要很多调试工程师来定位各种稀奇古怪的问题。第三,在追求高性能、高可靠性的某些领域里,仍需要优秀的人类程序员来编写极端精致的代码。就像在机器可以包饺子的今天,仍有某些饺子店使用人工包。
其实,不管我的预测是否对,一名好的程序员都应该不断锤炼自己的编码能力,提高技术水平,让自己写出的代码越来越好。
于是,可能有人问,我已经能写出很漂亮的代码,什么样的代码算是更好呢?
的确,评价代码好坏的标准有很多。在我看来,第一个硬指标就是generic,也就是通用性。展开来说,很多代码都有的一个通病就是长相类似的代码有很多份,结构类似,但有差异,不完全相同。
我是信儒家的,但偶尔也会读一点道家的作品,一般是在睡前读,因为读道家的作品读着读着就昏昏欲睡了。为什么呢?因为道家的话一般都比较“虚空”。用时髦的话说,就是不接地气,难以琢磨。比如一句“道可道,非常道”就有很多种解释。
我对道家的这种态度持续了很多年,直到有一天,当我领悟了计算机世界的一系列经典案例和一个永恒规律后,我又看到了“玄之又玄,众妙之门”。这八个字归纳得太好了,说出我心中所有,笔下所无,改变了我对道家的态度。
什么是玄而又玄呢?传统的解释有很多种,对多数程序员来说,都不大好理解。
在我看来,玄就是抽象。玄之又玄,就是抽象了再抽象。
人类的大脑喜欢生动具体的东西,比如小孩子都喜欢听故事,无论是“小马过河”还是“后羿射日”都有具体的场景、“人”和物。长大了以后喜欢刷剧也是类似的原因。每部剧都在一个具体的时空中讲一个故事。没有哪部剧没有人物,只有“道可道,非常道”。
因此,做抽象是很难的事情。也因此,很多代码都是不够抽象的,今天需要int类型的max()函数,那么就写个int类型的;明天需要float类型的,就把int类型的复制一份,改成float类型的。日积月累,整个项目里就有很多长相类似的代码了。
如何提炼这样的代码,消除重复,把它们合众为一呢?
传统C 中的模板技术就是为解决这个问题而设计的,现代C 将其发扬光大, 去除约束,增加功能,使其成为现代C 语言的一大亮点。
我认识文波和荣华多年,他们都在C 语言和编程技术领域耕耘多年,孜孜不倦,满怀深情。更加可贵的是,他们把热爱转化为实际的行动,以各种形式推动技术的传播和发展。他们在翻译《C 模板》(第2版)之后,又将另一本模板编程的好书《C 20模板元编程》翻译成中文,功莫大焉。
张银奎
《软件调试》和《软件简史》的作者
译 者 序
C 的演化与模板的历史
自1979年Bjarne Stroustrup 创建C 以来,这门语言经历了多个重要的标准化版本,每一次演进都带来了新的特性和改进。从C 98的标准化到C 11迎来现代C 编程范式,再到C 14、C 17的稳定和扩展,现在C 20作为一个里程碑式的更新,引入了概念(Concepts)、范围(Ranges)、协程(Coroutines)等强大特性。其中,C 20对模板系统的扩展和改进,使得泛型编程更加直观、高效。
C 模板的历史可以追溯到20世纪80年代后期,它最初是为了解决代码复用的问题。1998年的C 标准(C 98)正式引入了模板,随后在C 11中得到了重要增强,如变参模板(Variadic Templates)、模板别名(Template Aliases)等。C 17进一步引入了折叠表达式(Fold Expressions)和类模板实参推导(Class Template Argument Deduction,CTAD)。到了C 20,概念(Concepts)的加入使得模板的可读性、可维护性大幅提升。
C 模板的优势
C 是一门支持多种编程范式的语言,包括:
●过程式编程(Procedural Programming)——基于函数和过程的结构化编程。
●面向对象编程(OOP)——通过类、继承和多态实现模块化与复用。
●泛型编程(Generic Programming)——借助模板编写类型无关的代码,提高代码复用性和灵活性。
●函数式编程(Functional Programming)——使用不可变数据和高阶函数,提升代码可测试性和并发能力。
●元编程(Metaprogramming)——利用编译期计算优化程序,提高运行效率。
在这些范式中,模板技术是C 的核心特性,它赋予C 强大的泛型编程能力,使代码适用于多种数据类型,而不需要冗余编写。例如,标准模板库(STL)的容器(如 std::vector、std::map)和算法(如 std::sort、std::find)均依赖模板实现。
C 模板的主要优势包括:
●编译时多态(Compile-time Polymorphism)——相比运行时多态(如继承与虚函数),模板允许编译期进行类型推导和优化,从而提高执行效率。
●编译时计算(Compile-time Computation)——利用模板元编程(TMP),C 能在编译期执行计算,减少运行时开销。例如,std::integral_constant 和 std::conditional 可用于选择编译期代码路径。
●代码复用——模板减少了重复代码,提高了通用性。例如,std::enable_if 可用于 SFINAE(替换失败非错误),实现条件编译。
模板的强大使其在现代C 开发中占据重要地位,特别是在高性能计算、游戏开发、底层系统编程等领域。掌握模板不仅能提升代码质量,还能帮助程序员深入理解C 语言的底层机制。
C 程序员的技能
对于希望深入掌握C 的开发者而言,理解模板是进阶C 编程的必经之路。从泛型编程(Generic Programming)、模板元编程(Template Metaprogramming),到C 20 概念(Concepts),这些技术都在现代C 开发中占据了重要地位。
无论是编写高效的库函数,还是优化应用程序的性能,模板都是必不可少的工具。例如,在高性能计算(HPC)、游戏开发、底层系统编程等领域,模板能够提供无与伦比的灵活性和效率。掌握模板不仅能够提高代码质量,还能帮助程序员更深入地理解C 语言的底层机制。
模板技术的学习建议
模板技术属于编译期编程,在学习过程中,建议结合反汇编,并善用Cpp Insights 等工具来观察模板实例化和生成的代码。
要系统学习模板技术,仅靠一本书是不够的。推荐阅读以下书籍:
●《C Templates (第2版·中文版)》[C Templates: The Complete Guide, 2nd Edition, (美)David Vandevoorde、(德)Nicolai M. Josuttis、(美)Douglas Gregor著,何荣华、王文斌、张毅峰、杨文波译,人民邮电出版社]——经典的C 模板书籍,全面介绍了模板技术。
●《编程原本》[Elements of ?Programming,(美)Alexnader Stepanov、(美) Paul McJones著,裘宗燕译,人民邮电出版社]和亚历山大的系列博文(https://www.stepanovpapers.com/)——进一步深入泛型编程。
●《C实战:核心技术与最佳实践》(吴咏炜著,人民邮电出版社)——现代C 最佳实践。
此外,学习模板技术不能只依赖理论,还需要实践。建议阅读并改造以下模板库:
1. fmt(std::format的实现)——不依赖领域知识,适合作为入门教材。
2. blaze高性能数学库——作者 Klaus Iglberger 是模板设计模式专家。
3. folly库——Andrei Alexandrescu 主导,适合学习模板元编程。
4. cutlass C 模板库——Nvidia 出品,适用于深度学习优化。
结语与感谢
C 模板的强大使得它成为现代C 开发的基石,而C 20的更新更是让模板变得更易用、更强大。本书的目标是帮助读者全面理解C 20模板的核心概念,并掌握如何在实际开发中高效地应用模板技术。希望本书能为你打开C 模板编程的大门,帮助你在C 领域更进一步。
本书的出版离不开各方的支持。我们衷心感谢 Bjarne Stroustrup教授,他的贡献不仅塑造了C 语言,也为全球开发者提供了深远的技术指导。
特别感谢清华大学出版社的编辑团队,他们在术语规范、技术表达及出版质量方面提供了宝贵的支持,付出了大量的辛勤工作,确保本书得以高质量呈现。我们也感谢C 社区的开发者们,你们的深入讨论与实践经验为我们提供了极大的启发。
尽管我们力求精确,但面对C 如此庞大而复杂的体系,难免仍有不足之处。我们诚恳欢迎读者通过出版社反馈意见,以便我们进一步完善后续的修订工作。希望本书能够帮助广大开发者更深入地理解C ,更高效地运用这门强大语言。
献给那些总是渴望学习更多的好奇心灵。
——Marius Bancila
贡 献 者
关于作者
Marius Bancila 是一位拥有20年经验的软件工程师,在业务应用程序开发和其他领域都有丰富的解决方案经验。他是Modern C Programming Cookbook和The Modern C Challenge的作者。他目前担任软件架构师,专注于微软技术,主要使用C 和C#开发桌面应用程序。他热衷于与他人分享技术专长,因此自2006年起一直被认定为微软C MVP,后来还获得了开发者技术领域的 MVP 称号。Marius 居住在罗马尼亚,活跃于各种在线社区。
关于审校者
Aleksei Goriachikh拥有超过8年的C 编程经验。2012年从俄罗斯的新西伯利亚国立大学获得数学硕士学位后,Aleksei曾参与一些计算数学和优化领域的研究项目、某CAD系统的几何内核开发,以及自动驾驶的多线程库开发。Aleksei 最近的专业兴趣是硅前建模。
前 言
几十年来,C 一直是世界上使用最广泛的编程语言之一。它的成功不仅仅归功于其提供的性能或者说它的易用性(许多人对此持不同意见),而更可能是由于它的多功能性。C 是一种通用的多范式编程语言,它融合了过程式、函数式和泛型编程。
泛型编程是一种编写代码的方式,例如函数和类等实体是按照稍后实例化的类型编写的。这些泛型实体仅在需要作为实参具化为特定类型时才会实例化,这些泛型实体在C 中称为模板。
元编程是一种编程技术,它使用模板(以及C 中的constexpr函数)在编译期生成代码,然后将其与剩余源代码合并以便编译最终程序。元编程意味着其输入或输出中至少有一个是类型。
正如《C 核心指南》(Bjarne Stroustrup和Herb Sutter维护的一份关于应该做什么和不应该做什么的文档)中所描述的那样,C 中的模板可谓声名狼藉。然而,它们使得泛型库成为可能,比如C 开发人员一直使用的C 标准库。无论你是自己编写模板,还是只使用他人编写的模板(比如标准容器或算法),模板都很可能是你日常编码的一部分。
本书旨在让读者对C 中可用的所有范围内的模板都有很好的理解(从基本语法到C 20中的概念),这是本书前两部分的重点内容。第Ⅲ部分会帮助你将新获得的知识付诸实践,并使用模板进行元编程。
本书适读人群
本书适合想要学习模板元编程的初学者、中级C 开发人员,以及希望快速掌握与模板相关的C 20新功能和各种惯用法和模式的高级C 开发人员。在开始阅读本书之前,必须具备基本的C 编程经验。
本书涵盖内容
第1章“模板简介”。通过几个简单的例子介绍了C 中模板元编程的概念,讨论了为什么我们需要模板以及模板的优缺点。
第2章“模板基础”。探讨了C 中所有形式的模板:函数模板、类模板、变量模板和别名模板。我们讨论了其中每一个的语法和它们如何工作的细节。此外,还讨论了模板实例化和特化的关键概念。
第3章“变参模板”。专门介绍了变参模板,即具有可变数量模板形参的模板。我们详细讨论了变参函数模板、变参类模板、变参别名模板和变参变量模板、形参包及其展开方式,以及帮助我们简化编写变参模板的折叠表达式。
第4章“高级模板概念”。对一系列高级模板概念进行了分组,比如依赖名称和名称查找、模板实参推导、模板递归、完美转发、泛型和模板lambda函数。通过了解这些主题,读者将能够极大地扩展他们可以阅读或编写的模板的种类。
第5章“类型特征和条件编译”。专门讨论类型特征。读者将了解类型特征、标准库提供的特征以及如何使用它们解决不同的问题。
第6章“概念和约束”。介绍了新的C 20机制,通过概念和约束定义模板实参的需求。你将了解指定约束的各种方法。此外,还概述了C 20标准概念库的内容。
第7章“模式和惯用法”。探讨了一系列独立的高级主题,即利用迄今为止学到的知识实现各种模式。我们探讨了静态多态、类型擦除、标签派发和模式的概念,比如奇异递归模板模式、表达式模板、混入和类型列表。
第8章“范围和算法”。专注于理解容器、迭代器和算法,它们是标准模板库的核心组件。你将在这里学习如何为其编写泛型容器和迭代器类型以及通用算法。
第9章“范围库”。探讨了新的C 20范围库及其关键特性,例如范围、范围适配器和约束算法。这些使我们能够编写更简单的代码来处理范围。此外,你还将在这里学习如何编写自己的范围适配器。
附录是一个简短的结语,提供了本书的总结。
问题答案包含了所有章节中习题的答案。
充分利用本书
要开始阅读本书,首先需要对C 编程语言有一些基本的了解。需要了解有关类、函数、运算符、函数重载、继承、虚函数等的语法和基础知识。不过,对模板知识不做要求,因为本书将从头开始教你一切。
本书中的所有代码示例都是跨平台的。这意味着你可以使用任何编译器来构建和运行它们。然而,尽管许多代码段适用于C 11编译器,但也有一些代码段需要兼容C 17或C 20的编译器。因此,建议你使用支持C 20的编译器版本,以便运行所有示例。书中的示例已使用MSVC 19.30 (Visual Studio 2022)、GCC 12.1/13和Clang 13/14进行了测试。如果你的机器上没有这样一个兼容C 20的编译器,可以试着网上下载一个。我们推荐以下几个方案:
●Compiler Explorer (https://godbolt.org/)
●Wandbox (https://wandbox.org/)
●C Insights (https://cppinsights.io/)
本书多次引用C Insights在线工具来分析编译器生成的代码。
如果你想检查编译器对不同版本的C 标准的支持,应该参考页面https://en.cppreference.com/w/cpp/compiler_support。
提及标准和延伸阅读
在本书中,我们会多次提到C 标准。此文件版权归国际标准化组织所有。官方的C 标准文档可以从这里购买:https://www.iso.org/standard/79358.html。但是,C 标准的多个草案以及相应源码可以在GitHub上免费获得,网址为https://github.com/ cplusplus/draft。可以在https://isocpp.org/ std/the-standard链接上找到有关C 标准的更多信息。
C Reference网站是C 开发人员的一个很好的在线资源,网址为https://en. cppreference.com/。它提供了直接派生自C 标准的C 语言的详尽文档。本书多次引用了C 参考中的内容。C 参考的内容是基于CC-BY-SA协议的,https://en.cppreference. com/w/Cppreference:Copyright/CC-BY-SA。
(在每一章的末尾,你会发现一个名为“延伸阅读”的部分,该部分包含一份用作参考书目的阅读材料清单,推荐阅读以加深对所介绍主题的理解。)
下载示例代码文件
可以从GitHub上下载本书的示例代码文件,网址为https://github.com/ PacktPublishing/Template-Metaprogramming-with-CPP。也可以扫描封底二维码下载。如果代码有更新,将会在GitHub仓库中更新它。
下载彩图
我们还提供了一个PDF文件,其中包含本书中使用的屏幕截图和图表的彩图。可以在此处下载:https://packt.link/Un8j5。也可以扫描封底二维码下载。
使用的约定
本书使用了一些文本约定。
文本中的代码:表示文本中的代码词汇、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟URL、用户输入和Twitter用户名/账号标识。这里有一个例子:“这个问题可以通过将init设置为依赖名称来解决。”
代码块的格式如下:
template
structparser:base_parser
{
voidparse()
{
this->init(); // 正确
std::cout<<”parse\”;
}
};
按如下方式编写任意命令行的输入或输出:
fatal error:recursive template instantiation exceeded maximum depth of 1024
use -ftemplate-depth=N to increase recursive template instantiation depth
粗体:表示一个新术语、一个重要单词或你在屏幕上看到的单词。例如,菜单或对话框中的单词以粗体显示。这里有一个例子:“容量为8,大小为0,头部和尾部都指向索引0。”
提示或重要说明
迭代器概念在第6章“概念与约束”中进行了简要讨论。
本书的参考文献和问题答案可扫描封底二维码下载。