1.简介

C++11 增加了一个新特性变参模板(variadic template),它可以接受任意个模版参数,参数包不能直接展开,需要通过一些特殊的方法,比如函数参数包的展开可以使用递归方式或者逗号表达式,在使用的时候有点难度。C++17 解决了这个问题,通过fold expression(折叠表达式)简化对参数包的展开。

2.语法形式

折叠表达式共有四种语法形式,分别为一元的左折叠和右折叠,以及二元的左折叠和右折叠。

一元左折叠(unary left fold)
( ... op pack )
一元左折叠 (... op E) 展开之后变为 ((E1 op E2) op ...) op En一元右折叠(unary right fold)
( pack op ... )
一元右折叠 (E op ...) 展开之后变为 E1 op (... op (En-1 op En))二元左折叠(binary left fold)
( init op ... op pack )
二元左折叠 (I op ... op E) 展开之后变为 (((I op E1) op E2) op ...) op En二元右折叠(binary right fold)
( pack op ... op init )
二元右折叠 (E op ... op I) 展开之后变为 E1 op (... op (EN−1 op (EN op I)))

(1)语法形式中的op代表运算符,pack代表参数包,init代表初始值。
(2)不指定初始值的为一元折叠表达式,而指定初始值的为二元折叠表达式。
(3)初始值在右边的为右折叠,展开之后从右边开始折叠。而初始值在左边的为左折叠,展开之后从左边开始折叠。
(4)当一元折叠表达式中的参数包为空时,只有三个运算符(&& || 以及逗号)有缺省值,其中&&的缺省值为true,||的缺省值为false,逗号的缺省值为void()。
fold expression支持32种操作符:

+ - * / % ^ & | = < > << >> += -= *= /= %= ^= &= |= <<= >>= == != <= >= && || , .* ->*

3.使用实例

(1)一元右折叠
从表达式右边开始fold,看它是left fold还是right fold我们可以根据参数包…所在的位置来判断,当参数包…在操作符右边的时候就是right fold,在左边的时候就是left fold。示例如下:

template<typename... Args>
auto add_val(Args&&... args)
{return (args + ...);
}auto t = add_val(1,2,3,4); //10

(2)一元左折叠
对于+这种满足交换律的操作符来说,left fold和right fold是一样的,比如上面的例子你也可以写成left fold。

template<typename... Args>
auto add_val(Args&&... args)
{return (... + args);
}auto t = add_val(1,2,3,4); //10

对于不满足交换律的操作符来说就要注意了,比如减法,下面的right fold和left fold的结果就不一样。

template<typename... Args>
auto sub_val_right(Args&&... args)
{return (args - ...);
}template<typename... Args>
auto sub_val_left(Args&&... args)
{return (... - args);
}auto t = sub_val_right(2,3,4); //(2-(3-4)) = 3
auto t1 = sub_val_left(2,3,4); //((2-3)-4) = -5

(3)二元右折叠
二元fold的语义和一元fold的语义是相同的,参数包…在左即二元左折叠,参数包…在右即右折叠。下面看一个二元右折叠的例子。

template<typename... Args>
auto sub_one_left(Args&&... args)
{return (1 - ... - args);
}
auto t = sub_one_right(2,3,4);//(2-(3-(4-1))) = 2

(4)二元左折叠

template<typename... Args>
auto sub_one_right(Args&&... args)
{return (args - ... - 1);
}
auto t = sub_one_left(2,3,4);// (((1-2)-3)-4) = -8

(5)comma fold
在C++17之前,我们经常使用逗号表达式结合列表初始化的方式对参数包进行展开,比如像下面这个例子:

template<typename T>
void print_arg(T t)
{std::cout << t << std::endl;
}template<typename... Args>
void print2(Args... args)
{int a[] = { (print_arg(args), 0)... };//或者//std::initializer_list<int>{(print_arg(args), 0)...};
}

这种写法比较繁琐,用fold expression就会变得很简单了。

//unary right fold
template<typename... Args>
void print3(Args... args)
{(print_arg(args), ...);
}//unary left fold
template<typename... Args>
void print3(Args... args)
{(..., print_arg(args));
}

unary right fold和unary left fold,对于comma来说两种写法是一样的,参数都是从左至右传入print_arg函数。当然,我们也可以通过binary fold实现:

template<typename ...Args>
void printer(Args&&... args){(std::cout << ... << args) << '\n';
}

注意,下面的写法是不合法的,根据binary fold的语法,参数包…必须在操作符中间。

template<typename ...Args>
void printer(Args&&... args)
{(std::cout << args << ...) << '\n';
}

参考文献

[1]C++17中那些值得关注的特性(上)
[2]C++17尝鲜:fold expression(折叠表达式)

C++17 fold expression相关推荐

  1. C++17中那些值得关注的特性(上)

    C++17标准在2017上半年已经讨论确定,正在形成ISO标准文档,今年晚些时候会正式发布.本文将介绍最新标准中值得开发者关注的新特新和基本用法. 总的来说C++17相比C++11的新特性来说新特性不 ...

  2. C++17中那些值得关注的特性

    2019独角兽企业重金招聘Python工程师标准>>> C++17标准在2017上半年已经讨论确定,正在形成ISO标准文档,今年晚些时候会正式发布.本文将介绍最新标准中值得开发者关注 ...

  3. C++17之折叠表达式

    从c++ 17起,有一个特性可以计算在一个参数包的所有参数上使用二进制运算符的结果(带有一个可选的初值). 例如,下面的函数返回所有传递参数的和: #include <iostream> ...

  4. 【C++ 泛型编程 高级篇】 C++ 17 解析std::apply 的多种应用场景

    目录标题 1. 引言 1.1. C++17标准的引入 1.2. std::apply的基本概念 2. std::apply的基本用法 2.1. std::apply的函数签名 2.2. std::ap ...

  5. c ++函数功能查询器_C ++ 17新功能和技巧

    c ++函数功能查询器 目录 (Table of Contents) Introduction 介绍 Settings an integrated development environment (I ...

  6. 华硕灵耀 X Fold评测

    华硕灵耀 X Fold 笔记本国行版本,17.3 英寸 4:3 折叠屏,12 代酷睿 + 16GB 内存 + 1TB SSD,首发 19999 元. 这款笔记本配备一块 17.3 英寸 4:3 2.5 ...

  7. 安装GCC-8.3.0及其依赖

    目录 目录 1 1. 前言 1 2. 安装日期 1 3. GCC国内镜像下载地址 2 4. GCC的依赖库 2 4.1. gmp库 2 4.2. mpfr库 2 4.3. mpc库 2 4.4. m4 ...

  8. 变长参数模板 和 外部模板

    变长参数模板 解释 C++03只有固定模板参数.C++11 加入新的表示法,允许任意个数.任意类别的模板参数,不必在定义时将参数的个数固定. 变长模板.变长参数是依靠C++11新引入的参数包的机制实现 ...

  9. C++Template 模版的本质

    我想知道上帝的構思,其他的都祇是細節.                                                                                 ...

最新文章

  1. 爬一爬 iPhone 11为何嘴上说真丑,销量却真香?
  2. Leangoo敏捷开发项目管理平台新增测试用例管理、测试结果统计功能
  3. 8个开发必备的PHP功能
  4. 产品图片无缝水平滚动效果代码
  5. 命令行下从bak文件恢复sqlserver数据库方法
  6. TypeScript 里的 module 概念
  7. mysql 核对_核对数据库表记录的shell脚本
  8. 视觉开发需要什么程度的数学_角度的概念在视觉上非常直观,但其数学定义并不是那么简单...
  9. oracle 中表,oracle中表操作
  10. 【计算几何】FZU Problem 2270 Two Triangles
  11. 审计导致select * 报ORA-01435: user does not exist
  12. js 取get过来的数据
  13. python的requests模块功能_python-Requests模块的使用
  14. 初学者入门——NOI题库1.3
  15. jquery validate 验证单个
  16. Linux命令分隔符
  17. adb 连接安卓手机远程调试
  18. 储能变电站互动系统通讯协议 (征求意见稿)
  19. linux命令之 comm 使用
  20. 关于部分VPython差异

热门文章

  1. java 异常处理 Throwable Error 和Exception
  2. Matlab中bsxfun和unique函数解析
  3. windows2003密码忘记了该如何处理
  4. (二)Graphivz 简单结构图及子图
  5. linux redis客户端怎么使用,linux 下安装redis并用QT写客户端程序进行连接
  6. php数据库添加会员等级显示,给ECSHOP后台订单列表加上显示会员等级
  7. new blob文件设置编码_前端下载文件amp;下载进度
  8. python 网络编程_python网络编程示例(客户端与服务端)
  9. Java 实例 - 查找 List 中的最大最小值
  10. package.json 入门