内容简介
谢丙堃,从事 C++ 开发工作十余年,先后在数家知名互联网公司担任 C++ 高级开发工程师、技术专家和技术经理。他也是 C++ 语言的爱好者,热衷于研究 C++ 语言的新特性以及 C++ 模板元编程技术。
作品目录
第1章 新基础类型(C++11~C++20) 1
1.1 整数类型long long 1
1.2 新字符类型char16_t和char32_t 4
1.2.1 字符集和编码方法 4
1.2.2 使用新字符类型char16_t和char32_t 5
1.2.3 wchar_t存在的问题 6
1.2.4 新字符串连接 7
1.2.5 库对新字符类型的支持 7
1.3 char8_t字符类型 8
1.4 总结 8
第2章 内联和嵌套命名空间(C++11~C++20) 9
2.1 内联命名空间的定义和使用 9
2.2 嵌套命名空间的简化语法 11
2.3 总结 13
第3章 auto占位符(C++11~C++17) 14
3.1 重新定义的auto关键字 14
3.2 推导规则 16
3.3 什么时候使用auto 18
3.4 返回类型推导 20
3.5 lambda表达式中使用auto类型推导 20
3.6 非类型模板形参占位符 21
3.7 总结 22
第4章 decltype说明符(C++11~C++17) 23
4.1 回顾typeof和typeid 23
4.2 使用decltype说明符 24
4.3 推导规则 27
4.4 cv限定符的推导 29
4.5 decltype(auto) 30
4.6 decltype(auto)作为非类型模板形参占位符 31
4.7 总结 32
第5章 函数返回类型后置(C++11) 33
5.1 使用函数返回类型后置声明函数 33
5.2 推导函数模板返回类型 34
5.3 总结 36
第6章 右值引用(C++11 C++17 C++20) 37
6.1 左值和右值 37
6.2 左值引用 39
6.3 右值引用 40
6.4 右值的性能优化空间 42
6.5 移动语义 43
6.6 值类别 47
6.7 将左值转换为右值 48
6.8 万能引用和引用折叠 50
6.9 完美转发 52
6.10 针对局部变量和右值引用的隐式移动操作 55
6.11 总结 57
第7章 lambda表达式(C++11~C++20) 58
7.1 lambda表达式语法 58
7.2 捕获列表 60
7.2.1 作用域 60
7.2.2 捕获值和捕获引用 61
7.2.3 特殊的捕获方法 64
7.3 lambda表达式的实现原理 65
7.4 无状态lambda表达式 68
7.5 在STL中使用lambda表达式 68
7.6 广义捕获 69
7.7 泛型lambda表达式 72
7.8 常量lambda表达式和捕获*this 72
7.9 捕获[=, this] 73
7.10 模板语法的泛型lambda表达式 74
7.11 可构造和可赋值的无状态lambda表达式 76
7.12 总结 77
第8章 非静态数据成员默认初始化(C++11 C++20) 78
8.1 使用默认初始化 78
8.2 位域的默认初始化 79
8.3 总结 80
第9章 列表初始化(C++11 C++20) 81
9.1 回顾变量初始化 81
9.2 使用列表初始化 82
9.3 std::initializer_list详解 84
9.4 使用列表初始化的注意事项 86
9.4.1 隐式缩窄转换问题 86
9.4.2 列表初始化的优先级问题 87
9.5 指定初始化 88
9.6 总结 90
第10章 默认和删除函数(C++11) 91
10.1 类的特殊成员函数 91
10.2 显式默认和显式删除 95
10.3 显式删除的其他用法 98
10.4 explicit和=delete 99
10.5 总结 100
第11章 非受限联合类型(C++11) 101
11.1 联合类型在C++中的局限性 101
11.2 使用非受限联合类型 102
11.3 总结 106
第12章 委托构造函数(C++11) 107
12.1 冗余的构造函数 107
12.2 委托构造函数 110
12.3 委托模板构造函数 114
12.4 捕获委托构造函数的异常 115
12.5 委托参数较少的构造函数 116
12.6 总结 117
第13章 继承构造函数(C++11) 118
13.1 继承关系中构造函数的困局 118
13.2 使用继承构造函数 119
13.3 总结 123
第14章 强枚举类型(C++11 C++17 C++20) 124
14.1 枚举类型的弊端 124
14.2 使用强枚举类型 129
14.3 列表初始化有底层类型枚举对象 131
14.4 使用using打开强枚举类型 133
14.5 总结 135
第15章 扩展的聚合类型(C++17 C++20) 136
15.1 聚合类型的新定义 136
15.2 聚合类型的初始化 137
15.3 扩展聚合类型的兼容问题 139
15.4 禁止聚合类型使用用户声明的构造函数 140
15.5 使用带小括号的列表初始化聚合类型对象 142
15.6 总结 143
第16章 override和final说明符(C++11) 144
16.1 重写、重载和隐藏 144
16.2 重写引发的问题 145
16.3 使用override说明符 145
16.4 使用final说明符 146
16.5 override和final说明符的特别之处 148
16.6 总结 148
第17章 基于范围的for循环(C++11 C++17 C++20) 149
17.1 烦琐的容器遍历 149
17.2 基于范围的for循环语法 150
17.3 begin和end函数不必返回相同类型 151
17.4 临时范围表达式的陷阱 152
17.5 实现一个支持基于范围的for循环的类 153
17.6 总结 155
第18章 支持初始化语句的if和switch(C++17) 156
18.1 支持初始化语句的if 156
18.2 支持初始化语句的switch 159
18.3 总结 160
第19章 static_assert声明 161
19.1 运行时断言 161
19.2 静态断言的需求 162
19.3 静态断言 163
19.4 单参数static_assert 164
19.5 总结 165
第20章 结构化绑定(C++17 C++20) 166
20.1 使用结构化绑定 166
20.2 深入理解结构化绑定 169
20.3 结构化绑定的3种类型 171
20.3.1 绑定到原生数组 171
20.3.2 绑定到结构体和类对象 172
20.3.3 绑定到元组和类元组的对象 173
20.4 实现一个类元组类型 175
20.5 绑定的访问权限问题 178
20.6 总结 179
第21章 noexcept关键字(C++11 C++17 C++20) 180
21.1 使用noexcept代替throw 180
21.2 用noexcept来解决移动构造问题 183
21.3 noexcept和throw() 185
21.4 默认使用noexcept的函数 186
21.5 使用noexcept的时机 189
21.6 将异常规范作为类型的一部分 190
21.7 总结 192
第22章 类型别名和别名模板(C++11 C++14) 193
22.1 类型别名 193
22.2 别名模板 194
22.3 总结 196
第23章 指针字面量nullptr(C++11) 197
23.1 零值整数字面量 197
23.2 nullptr关键字 198
23.3 总结 201
第24章 三向比较(C++20) 202
24.1 “太空飞船”(spaceship)运算符 202
24.2 三向比较的返回类型 202
24.2.1 std::strong_ordering 203
24.2.2 std::weak_ordering 204
24.2.3 std::partial_ordering 205
24.3 对基础类型的支持 206
24.4 自动生成的比较运算符函数 207
24.5 兼容旧代码 210
24.6 总结 211
第25章 线程局部存储(C++11) 212
25.1 操作系统和编译器对线程局部存储的支持 212
25.2 thread_local说明符 213
25.3 总结 217
第26章 扩展的inline说明符(C++17) 218
26.1 定义非常量静态成员变量的问题 218
26.2 使用inline说明符 219
26.3 总结 220
第27章 常量表达式(C++11~C++20) 221
27.1 常量的不确定性 221
27.2 constexpr值 224
27.3 constexpr函数 225
27.4 constexpr构造函数 228
27.5 对浮点的支持 230
27.6 C++14标准对常量表达式函数的增强 230
27.7 constexpr lambdas表达式 233
27.8 constexpr的内联属性 235
27.9 if constexpr 236
27.10 允许constexpr虚函数 240
27.11 允许在constexpr函数中出现Try-catch 244
27.12 允许在constexpr中进行平凡的默认初始化 244
27.13 允许在constexpr中更改联合类型的有效成员 245
27.14 使用consteval声明立即函数 246
27.15 使用constinit检查常量初始化 247
27.16 判断常量求值环境 248
27.17 总结 252
第28章 确定的表达式求值顺序(C++17) 253
28.1 表达式求值顺序的不确定性 253
28.2 表达式求值顺序详解 254
28.3 总结 255
第29章 字面量优化(C++11~C++17) 257
29.1 十六进制浮点字面量 257
29.2 二进制整数字面量 258
29.3 单引号作为整数分隔符 258
29.4 原生字符串字面量 259
29.5 用户自定义字面量 261
29.6 总结 267
第30章 alignas和alignof(C++11 C++17) 268
30.1 不可忽视的数据对齐问题 268
30.2 C++11标准之前控制数据对齐的方法 270
30.3 使用alignof运算符 272
30.4 使用alignas说明符 273
30.5 其他关于对齐字节长度的支持 276
30.6 C++17中使用new分配指定对齐字节长度的对象 278
30.7 总结 279
第31章 属性说明符和标准属性(C++11~C++20) 280
31.1 GCC的属性语法 280
31.2 MSVC的属性语法 281
31.3 标准属性说明符语法 282
31.4 使用using打开属性的命名空间 283
31.5 标准属性 283
31.5.1 noreturn 284
31.5.2 carries_dependency 286
31.5.3 deprecated 286
31.5.4 fallthrough 287
31.5.5 nodiscard 288
31.5.6 maybe_unused 290
31.5.7 likely和unlikely 290
31.5.8 no_unique_address 291
31.6 总结 293
第32章 新增预处理器和宏(C++17 C++20) 294
32.1 预处理器__has_include 294
32.2 特性测试宏 295
32.2.1 属性特性测试宏 295
32.2.2 语言功能特性测试宏 295
32.2.3 标准库功能特性测试宏 297
32.3 新增宏__VA_OPT__ 301
32.4 总结 302
第33章 协程(C++20) 303
33.1 协程的使用方法 303
33.2 协程的实现原理 308
33.2.1 co_await运算符原理 308
33.2.2 co_yield运算符原理 313
33.2.3 co_return运算符原理 317
33.2.4 promise_type的其他功能 319
33.3 总结 320
第34章 基础特性的其他优化(C++11~C++20) 321
34.1 显式自定义类型转换运算符(C++11) 321
34.2 关于std::launder()(C++17) 325
34.3 返回值优化(C++11~C++17) 326
34.4 允许按值进行默认比较(C++20) 333
34.5 支持new表达式推导数组长度(C++20) 334
34.6 允许数组转换为未知范围的数组(C++20) 335
34.7 在delete运算符函数中析构对象(C++20) 336
34.8 调用伪析构函数结束对象声明周期(C++20) 337
34.9 修复const和默认复制构造函数不匹配造成无法编译的问题(C++20) 338
34.10 不推荐使用volatile的情况(C++20) 339
34.11 不推荐在下标表达式中使用逗号运算符(C++20) 340
34.12 模块(C++20) 340
34.13 总结 341
第35章 可变参数模板(C++11 C++17 C++20) 342
35.1 可变参数模板的概念和语法 342
35.2 形参包展开 344
35.3 sizeof...运算符 352
35.4 可变参数模板的递归计算 353
35.5 折叠表达式 354
35.6 一元折叠表达式中空参数包的特殊处理 357
35.7 using声明中的包展开 358
35.8 lambda表达式初始化捕获的包展开 359
35.9 总结 361
第36章 typename优化(C++17 C++20) 362
36.1 允许使用typename声明模板形参 362
36.2 减少typename使用的必要性 363
36.3 总结 365
第37章 模板参数优化(C++11 C++17 C++20) 366
37.1 允许常量求值作为所有非类型模板的实参 366
37.2 允许局部和匿名类型作为模板实参 368
37.3 允许函数模板的默认模板参数 369
37.4 函数模板添加到ADL查找规则 370
37.5 允许非类型模板形参中的字面量类类型 371
37.6 扩展的模板参数匹配规则 373
37.7 总结 374
第38章 类模板的模板实参推导(C++17 C++20) 375
38.1 通过初始化构造推导类模板的模板实参 375
38.2 拷贝初始化优先 377
38.3 lambda类型的用途 378
38.4 别名模板的类模板实参推导 380
38.5 聚合类型的类模板实参推导 380
38.6 总结 382
第39章 用户自定义推导指引(C++17) 383
39.1 使用自定义推导指引推导模板实例 383
39.2 聚合类型类模板的推导指引 386
39.3 总结 387
第40章 SFINAE(C++11) 388
40.1 替换失败和编译错误 388
40.2 SFINAE规则详解 389
40.3 总结 394
第41章 概念和约束(C++20) 395
41.1 使用std::enable_if约束模板 395
41.2 概念的背景介绍 396
41.3 使用concept和约束表达式定义概念 397
41.4 requires子句和约束检查顺序 398
41.5 原子约束 401
41.6 requires表达式 403
41.6.1 简单要求 404
41.6.2 类型要求 405
41.6.3 复合要求 405
41.6.4 嵌套要求 406
41.7 约束可变参数模板 407
41.8 约束类模板特化 408
41.9 约束auto 409
41.10 总结 410
第42章 模板特性的其他优化(C++11 C++14) 411
42.1 外部模板(C++11) 411
42.2 连续右尖括号的解析优化(C++11) 413
42.3 friend声明模板形参(C++11) 415
42.4 变量模板(C++14) 417
42.5 explicit(bool) 419
42.6 总结 423
附录 特性章节对照表 424
· · · · · ·
作者简介
谢丙堃,从事 C++ 开发工作十余年,先后在数家知名互联网公司担任 C++ 高级开发工程师、技术专家和技术经理。他也是 C++ 语言的爱好者,热衷于研究 C++ 语言的新特性以及 C++ 模板元编程技术。