作者:jinshang
步入现代C++时代开始,C++语言标准形成了三年一个版本的惯例:C++11标志着现代C++的开端,C++14在11的基础上查缺补漏,并未加入许多新特性,而C++17作为C++11后的第一个大版本,标志着现代C++逐渐走向成熟。WXG编译器升级到gcc7.5已有一段时间,笔者所在项目组也已经将全部代码升级到C++17。在使用了c++17一年多之后,笔者总结了C++17在业务代码中最好用的十个特性。
注1:本文只包含wxg的gcc7.5支持的特性,Execution Policy, File System等暂不支持的特性不包含在内。
注2:本文只包含应用于业务逻辑的特性,Fold Expression, Mathematical Special Functions等适用于元编程和科学计算的特性并不包含。
笔者将这些特性大体上分为三类:语法糖、性能提升和类型系统
语法糖
这里所说的语法糖,并不是严格意义上编程语言级别的语法糖,还包括一些能让代码更简洁更具有可读性的函数和库:
结构化绑定
c++17最便利的语法糖当属结构化绑定。结构化绑定是指将array、tuple或struct的成员绑定到一组变量*上的语法,最常用的场景是在遍历map/unordered_map时不用再声明一个中间变量了:
// pre c++17
for(const auto& kv: map){
const auto& key = kv.first;
const auto& value = kv.second;
// ...
}
// c++17
for(const auto& [key, value]: map){
// ...
}
严格来说,结构化绑定的结果并不是变量,c++标准称之为名字/别名,这也导致它们不允许被lambda捕获,但是gcc并没有遵循c++标准,所以以下代码在gcc可以编译,clang则编译不过
for(const auto& [key, value]: map){
[&key, &value]{
std::cout << key << ": " << value << std::endl;
}();
}
在clang环境下,可以在lambda表达式捕获时显式引入一个引用变量通过编译
for(const auto& [key, value]: map){
[&key = key, &value = value]{
std::cout << key << ": " << value << std::endl;
}();
}
另外这条限制在c++20中已经被删除,所以在c++20标准中gcc和clang都可以捕获结构化绑定的对象了。
std::tuple的隐式推导
在c++17以前,构造std::pair/std::tuple时必须指定数据类型或使用std::make_pair/std::make_tuple函数,c++17为std::pair/std::tuple新增了推导规则,可以不再显示指定类型。
// pre c++17
std::pair<int, std::string> p1{3.14, "pi"s};
auto p1 = std::make_pair(3.14, "pi"s);
// c++17
std::pair p3{3.14, "pi