C++17中的折叠表达式实现
前言
C++11提供了可变模板参数包,使函数可以接受任意数量的参数.但在C++11中展开参数包稍显麻烦,而C++17的折叠表达式使得展开参数包变得容易,其基本语法是使用(…)的语法形式进行展开。
支持的操作符
C++17中,折叠表达式支持32个操作符:
+,-,*,/,%,^,&,|,=,<, >,<<,>>,+=,-=,*=,/=,%=,^=,&=,|=,<<=, >>=,==,!=,<=,>=,&&,||,,,.*,->*.
折叠分类
折叠位置
1.左折叠
2.右折叠
操作数个数
1.一元折叠
2.二元折叠
例1:左折叠
templateautosum(Ts...ts) { return(...+ts); } intres{sum(1,2,3,4,5)}; std::stringa{"Hello"}; std::stringb{"World"}; std::stringstr_res{sum(a,b)};//a+b的结果
例2:右折叠
templateautosum(Ts...ts) { return(ts+...); }
例1中,参数包…位于操作符的左侧,故尔称为左折叠。如果…位于操作符右侧,则称为右折叠,如例2所示。就例1与例2而言,左折叠与右折叠的效果是相同的。
intres{sum(1,2,3,4,5)}; //左折叠的展开方式为 1+(2+(3+(4+5))), //右折叠的展开方式为 (((1+2)+3)+4)+5 //在例1与例2中,如果参数包包含的参数数量为0,即为空包,会产生编译错误,如 intthe_sum{sum()}; /*大致的错误输出如下 Ininstantiationof'autosum(Ts...)[withTs={}]': error:foldofemptyexpansionoveroperator+ return(...+ts); */
若要解决空参数包的编译错误,针对例1,可以加上一个数值0,可以解决编译错误又可以使得语义不变,这个0相当于缺省值。通过加上一个数值,折叠就变成了二元折叠,如例3所示。
例3:二元折叠
templateautosum(Ts...ts) { //二元右折叠 return(ts+...+0); //二元左折叠 //return(0+...+ts); }
此时对于intres{sum(1,2,3,4,5)};折叠的展开方式为
1+(2+(3+(4+(5+0))))
空参数包
空参数包就是参数包中不含任何参数。对于大多数操作符,空参数包将会引发编译错误。对于&&或||,空参数包是合法的,其中&&的展开结果为true,||的展开结果为false。在逗号,操作符中,空参数包也合法,展开为void()。
例4:计算指定区间内包含指定数值的个数
templateautocount(constR&range,Ts...ts) { return(std::count(std::begin(range),std::end(range),ts)+...); } ... std::vector v{1,2,3,4,5}; count(v,2,5);//returns2 count(v,100,200);//returns0 count("abcdefg",'x','y','z');//returns0 count("abcdefg",'a','d','f');//returns3
例5:检查插入多个元素是否成功
templateboolinsert_all(T&set,Ts...ts) { return(set.insert(ts).second&&...); } ... std::set my_set{1,2,3}; insert_all(my_set,4,5,6);//Returnstrue,my_set值为{1,2,3,4,5,6} insert_all(my_set,7,2,8);//Returnsfalse,my_set值为{1,2,3,4,5,6,7} //插入2时出错,8不会被插入
最后
1.对于一元右折叠(Eop…)具体展开为E1op(…op(EN-1opEN))。
2.对于一元左折叠(…opE)具体展开为((E1opE2)op…)opEn。
3.对于二元右折叠(Eop…opI)具体展开为E1op(…op(EN-1op(ENopI)))。
4.对于二元左折叠(Iop…opE)具体展开为(((IopE1)opE2)op…)opE2。
左折叠与右折叠的语义并非总是相同的。比如对于加法和乘法,左折叠与右折叠的语义是相同的,但是对于减法与除法,其语义是不同的。
例6:左右折叠不同语义
templateautoleft_sub(Args&&...args){ return(...-args); } template autoright_sub(Args&&...args){ return(args-...); } ... autoa=left_sub(2,3,4);//((2-)-3)-4)=-5 autob=right_sub(2,3,4);//(2-(3-4))=3
到此这篇关于C++17中的折叠表达式实现的文章就介绍到这了,更多相关C++17折叠表达式内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。