专栏首页C/C++基础C++17 fold expression

C++17 fold expression

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

参考文献

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • C/C++编码规范

    对于变成人员,良好的编程风格是提高程序可靠性和效率非常重要的手段。而编码规范就是对编程风格最好的约束保障。 严格遵守编码规范方便代码的交流和维护,利于提高代...

    Dabelv
  • Linux命令(56)——telnet命令

    telnet命令用于登录远程主机,是基于Telnet协议的远程登录程序,对远程主机进行管理。telnet因为采用明文传送报文,安全性不好,很多Linux服务器都...

    Dabelv
  • Linux命令(34)——vim命令

    vi命令是UNIX操作系统和类UNIX操作系统中最通用的全屏幕纯文本编辑器。Linux中的vi编辑器叫vim,它是vi的增强版(vi iMproved),与vi...

    Dabelv
  • HIVE中的表以及语法

    云飞扬
  • 恢复在WIN64上的SSDT钩子

    要恢复SSDT,首先要获得SSDT各个函数的原始地址,而SSDT各个函数的原始地址,自然是存储在内核文件里的。于是,有了以下思路:

    战神伽罗
  • 官方解读:TensorFlow 2.0中即将到来的所有新特性

    本文经机器之心(微信公众号:almosthuman2014)授权转载,禁止二次转载

    小小詹同学
  • 动态 | TensorFlow 2.0 新特性来啦,部分模型、库和 API 已经可以使用

    由于令人难以置信的多样化社区,TensorFlow 已经发展成为世界上最受欢迎和广泛采用的 ML 平台之一。这个社区包括:

    AI科技评论
  • TensorFlow 2.0 的新功能

    2018 年 11 月,TensorFlow 迎来了它的 3 岁生日,我们回顾了几年来它增加的功能,进而对另一个重要里程碑 TensorFlow 2.0 感到兴...

    磐创AI
  • 官方解读:TensorFlow 2.0中即将到来的所有新特性

    作为最流行的深度学习框架,TensorFlow 已经成长为全球使用最广泛的机器学习平台。目前,TensorFlow 的开发者社区包括研究者、开发者和企业等。

    机器之心
  • 什么是深度学习?

    什么是深度学习 深度学习,顾名思义,需要从“深度”和“学习”两方面来谈。 01 深度 深度学习的前身是人工神经网络(artificial neural netw...

    IT派

扫码关注云+社区

领取腾讯云代金券