C++17 几个新的语言特性
1. 结构化绑定声明
绑定指定名称到初始化器的子对象或元素。 通俗地讲,对形如 std::pair
、std::tuple
或自定义聚合类型的实例,可以声明一组变量直接指向其成员,无需创建一个对应聚合类型的临时变量:
1 | std::pair<int, int> point{ 0, 1 }; |
引用语法同样适用:
1 | // keys to values |
不过不能绑定到已声明变量上,还是要通过 std::tie()
绑定:
1 | int x = 0, y = 0; |
2. if & switch 内初始化语句
类似 for 循环的语法:if (init; condition)
、switch (init; condition)
可以将 init
语句内声明的变量的生命周期限制在 if else
、switch case
块内。优点显而易见,再也不用在外层作用域预先声明变量使其在 if else
内都可见了。极大程度上避免了名字污染问题。
1 | if (const auto pos = myString.find("World"); pos != std::string::npos) |
3. 类模版的模版参数推断
模版参数类型推断终于普及到类模板了。在这之前,创建一个 std::pair 对象最常用的方法不是直接构造,而是通过 std::make_pair()
函数:
1 | auto myPair = std::make_pair(42, "hello world"); |
为的就是利用函数模板的参数类型推断能力,可以少敲几下键盘。现在,类模版同样可以推断参数类型了:
1 | // before: |
对其它所有类模版同样适用:
1 | // before: |
1 | // before: |
4. 折叠表达式
展开一个参数包并对其中参数依次施以动作。算是对 C++11 里引入的变参模版的应用规则的一种优化吧。
折叠表达式支持 4 种形式的语法表达:
( pack op ... )
( ... op pack )
( pack op ... op init )
( init op ... op pack )
这里有详细的解释,比我在这胡说八道强多了。
一个经典的应用场景是日志打印:
1 | // 第四种语法的表现 |
输出的参数全挤在一起,这肯定不是想要的结果。可以改造下:
1 | // 第一种语法的表现 |
逗号左边两次输出以 () 包含,变成了一个表达式,等同于第一种语法的 pack 部分;‘,’ 即 op。整个表达式的意思就是对参数包内所有参数,先打印参数本身再打印一个空格符,依次操作。