C++17中的折叠表达式实现
前言

C++11 提供了可变模板参数包, 使函数可以接受任意数量的参数. 但在 C++11中展开参数包稍显麻烦, 而 C++17 的折叠表达式使得展开参数包变得容易, 其基本语法是使用 (…) 的语法形式进行展开。
支持的操作符
C++17中,折叠表达式支持 32 个操作符:
+, -, *, /, %, ^, &, |, =, <, >, <<, >>, +=, -=, *=, /=, %=, ^=, &=, |=, <<=, >>=,==, !=, <=, >=, &&, ||, ,, .*, ->*.
折叠分类
折叠位置
1.左折叠
2.右折叠
操作数个数
1.一元折叠
2.二元折叠
例 1: 左折叠
template <typename ... Ts>
auto sum(Ts ... ts)
{
return (... + ts);
}
int res{sum(1, 2, 3, 4, 5)};
std::string a{"Hello "};
std::string b{"World"};
std::string str_res {sum(a, b)};//a+b的结果
例 2: 右折叠
template <typename ... Ts>
auto sum(Ts ... ts)
{
return (ts + ...);
}
例 1 中, 参数包 … 位于操作符的左侧,故尔称为左折叠。 如果 …位于操作符右侧,则称为右折叠,如例 2 所示。就例 1 与例 2 而言,左折叠与右折叠的效果是相同的。
int res {sum(1, 2, 3, 4, 5)};
//左折叠的展开方式为
1 + (2 + (3 + (4 + 5))),
//右折叠的展开方式为
(((1 + 2) + 3) + 4) + 5
//在例 1 与 例 2 中,如果参数包包含的参数数量为 0,即为空包,会产生编译错误,如
int the_sum {sum()};
/*大致的错误输出如下
In instantiation of 'auto sum(Ts ...) [with Ts = {}]':
error: fold of empty expansion over operator+
return (... + ts);
*/
若要解决空参数包的编译错误,针对例 1,可以加上一个数值 0,可以解决编译错误又可以使得语义不变,这个 0 相当于缺省值。通过加上一个数值,折叠就变成了二元折叠,如例 3 所示。
例 3: 二元折叠
template <typename ... Ts>
auto sum(Ts ... ts)
{
// 二元右折叠
return (ts + ... + 0);
// 二元左折叠
// return (0 + ... + ts);
}
此时对于 int res{sum(1, 2, 3, 4, 5)};折叠的展开方式为
1 + (2 + (3 + (4 + (5 + 0))))
空参数包
空参数包就是参数包中不含任何参数。对于大多数操作符,空参数包将会引发编译错误。对于 && 或 ||,空参数包是合法的,其中 && 的展开结果为 true,||的展开结果为 false。在逗号 , 操作符中,空参数包也合法,展开为 void()。
例 4: 计算指定区间内包含指定数值的个数
template <typename R, typename ... Ts>
auto count(const R& range, Ts ... ts)
{
return (std::count(std::begin(range), std::end(range), ts) + ...);
}
...
std::vector<int> v {1, 2, 3, 4, 5};
count(v, 2, 5); // returns 2
count(v, 100, 200); // returns 0
count("abcdefg", 'x', 'y', 'z'); // returns 0
count("abcdefg", 'a', 'd', 'f'); // returns 3
例 5: 检查插入多个元素是否成功
template <typename T, typename ... Ts>
bool insert_all(T &set, Ts ... ts)
{
return (set.insert(ts).second && ...);
}
...
std::set<int> my_set {1, 2, 3};
insert_all(my_set, 4, 5, 6); // Returns true, my_set 值为 {1, 2, 3, 4, 5, 6}
insert_all(my_set, 7, 2, 8); // Returns false, my_set 值为 {1, 2, 3, 4, 5, 6, 7}
// 插入 2 时出错, 8 不会被插入
最后
1.对于一元右折叠 (E op …) 具体展开为 E1 op (… op (EN-1 op EN))。
2.对于一元左折叠 (… op E) 具体展开为 (( E1 op E2) op …) op En。
3.对于二元右折叠 (E op … op I) 具体展开为 E1 op (… op (EN-1 op (EN op I)))。
4.对于二元左折叠 (I op … op E) 具体展开为 (((I op E1) op E2) op …) op E2。
左折叠与右折叠的语义并非总是相同的。比如对于加法和乘法,左折叠与右折叠的语义是相同的,但是对于减法与除法,其语义是不同的。
例 6: 左右折叠不同语义
template<typename... Args>
auto left_sub(Args&&... args) {
return (... - args);
}
template<typename... Args>
auto right_sub(Args&&... args) {
return (args - ...);
}
...
auto a = left_sub(2, 3, 4); // ((2 - ) -3 ) - 4) = -5
auto b = right_sub(2, 3, 4); // (2 - (3 - 4)) = 3
代码知识SEO
上一篇 : Opencv python 图片生成视频的方法示例
下一篇 : vue在图片上传的时候压缩图片
-
SEO外包最佳选择国内专业的白帽SEO机构,熟知搜索算法,各行业企业站优化策略!
SEO公司
-
可定制SEO优化套餐基于整站优化与品牌搜索展现,定制个性化营销推广方案!
SEO套餐
-
SEO入门教程多年积累SEO实战案例,从新手到专家,从入门到精通,海量的SEO学习资料!
SEO教程
-
SEO项目资源高质量SEO项目资源,稀缺性外链,优质文案代写,老域名提权,云主机相关配置折扣!
SEO资源
-
SEO快速建站快速搭建符合搜索引擎友好的企业网站,协助备案,域名选择,服务器配置等相关服务!
SEO建站
-
快速搜索引擎优化建议没有任何SEO机构,可以承诺搜索引擎排名的具体位置,如果有,那么请您多注意!专业的SEO机构,一般情况下只能确保目标关键词进入到首页或者前几页,如果您有相关问题,欢迎咨询!