C++17 详解 1

本文为 《C++17 in detail》 一书的中文渣中渣译文,不足之处还望指正。

第一部分——语言特性

C++17 是对 C++ 的一次重大更新,引入了大量语言特性。大多数新增特性让 C++ 更简洁更直截了当。

在本部分你将学到:

  • 被移除和被标记为已弃用的特性
  • C++ 是如何变得更精准的:比如,借助表达式求值顺序保证
  • 模版相关新特性:比如 if constexpr、折叠表达式(fold expressions
  • 新的标准属性(attributes
  • 如何借助结构化绑定(structured binding)、内联变量(inline variables)、编译时 if 和类模版参数推导(template argument deduction for classes)写出更简洁更具表现力的代码

快速开始

为了激发你对新标准更多的好奇心,下面展示几段新特性组合使用的代码示例。

如果觉得示例太复杂也不用担心,因为它们把太多新东西混在了一起。所有新特性都会在接下来的章节进行单独深入解释。

使用 Map

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Example: Part I/demo_map.cpp
#include <iostream>
#include <map>

int main() {
std::map<std::string, int> mapUserAge{ {"Alex", 45}, {"John", 25} };

std::map mapCopy{ mapUserAge };

if (auto [iter, wasAdded] = mapCopy.insert_or_assign("John", 26); !wasAdded)
std::cout << iter->first << " reassigned...\n";

for (const auto &[key, value] : mapCopy)
std::cout << key << ", " << value << '\n';
}

代码输出如下:

1
2
3
John reassigned...
Alex, 45
John, 26

上边示例使用了如下特性:

  • 第 8 行:类模板参数推导—— mapCopy 类型从 mapUserAge 类型推断得来。不需要显式声明为 std::map<std::string, int> mapCopy{...}
  • 第 10 行:新的 map 插入函数—— insert_or_assign
  • 第 10 行:结构化绑定——捕获 insert_or_assign 返回的 pair 到两个分开的变量。
  • 第 10 行:带初始化的 if 语句—— iterwasAdded 只在 if 语句代码块内可见。
  • 第 13 行:基于范围的 forrange-based for)循环内的结构化绑定——可以用 keyvalue 代替 pair.first pair.second 进行迭代。

调试打印

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Example: Part I/demo_print.cpp
#include <iostream>

template<typename T> void linePrinter(const T &x) {
if constexpr (std::is_integral_v<T>)
std::cout << "num: " << x << '\n';
else if constexpr (std::is_floating_point_v<T>) {
const auto frac = x - static_cast<long>(x);
std::cout << "flt: " << x << ", frac " << frac << '\n';
}
else if constexpr (std::is_pointer_v<T>) {
std::cout << "ptr, ";
linePrinter(*x);
}
else
std::cout << x << '\n';
}

template <typename ... Args> void printWithInfo(Args ... args) {
(linePrinter(args), ...); // 逗号运算符上的折叠表达式
}

int main() {
int i = 10;
float f = 2.56f;
printWithInfo(&i, &f, 30);
}

代码输出如下:

1
2
3
ptr, num: 10
ptr, flt: 2.56, frac 0.56
num: 30

这里用到了以下特性:

  • 第 5、7、11 行:if constexpr ——用于匹配模版参数,以使编译时丢弃代码。
  • 第 5、7、11 行:类型萃取中 _v 样式的变量模版——不再需要写明 std::trait_name<T>::value
  • 第 20 行:printWithInfo 内的折叠表达式——此特性简化了可变参数模版。本例中我们对所有输入参数分别调用 linePrinter()

正式开始吧!

上边你看到的只是冰山一角,阅读接下来的章节你会看到更多:对当前语言的修复、阐明、移除(比如 auto_ptr),当然还有新增的一些东西:constexpr lambdaif constexpr,结构化绑定,template<auto>,内联变量,类模板参数推断以及更多。

评论