如何用折叠表达式实现短路式多米诺(级联)更新函数?
多米诺更新:用折叠表达式替代递归实现短路逻辑
我正在编写一个可变模板函数以实现「多米诺更新」:给定断言p,遍历多个左值(按引用传递)并将val赋值给它们,直到p(val, lval)返回false时停止。
我的当前递归实现如下:
#include <iostream> #include <functional> template<class Val, class P> void domino_update(P, Val&) {} template<class Val, class Lval, class... More, class P> void domino_update(P p, Val&& val, Lval& lval, More&... more) { if (p(val, lval)) { lval = val; // No need to forward since it'd potentially chain more copies anyway domino_update(p, val, more...); } } int main(int, char**) { int i = 8, j = 9, k = 1; domino_update(std::less{}, 2, i, j, k); std::cout << i << ' ' << j << ' ' << k << '\n'; // Prints 2 2 1 return 0; }
但我不喜欢递归实现,想改用折叠表达式避免递归(无需实现模板基例),同时保留短路逻辑(即p返回false后不再执行后续操作),该怎么做?
解决方案:利用折叠表达式的短路特性
可以借助C++17的折叠表达式结合辅助lambda,利用逻辑与&&的短路求值特性实现需求。核心思路是用&&连接每个左值的处理逻辑,一旦某个逻辑返回false,后续操作会被直接跳过。
实现代码如下:
#include <iostream> #include <functional> template<class P, class Val, class... Lvals> void domino_update(P p, Val val, Lvals&... lvals) { [[maybe_unused]] bool dummy = ( [&](auto& lval) -> bool { if (p(val, lval)) { lval = val; return true; } return false; }(lvals) && ... ); } int main(int, char**) { int i = 8, j = 9, k = 1; domino_update(std::less{}, 2, i, j, k); std::cout << i << ' ' << j << ' ' << k << '\n'; // 输出 2 2 1 return 0; }
代码细节说明
- 折叠表达式的短路性:
(lambda(lvals) && ...)是一元右折叠,会依次将每个lvals传入lambda执行,并用&&连接结果。由于&&的短路特性,只要其中一个lambda返回false,后续的lambda调用就会被终止。 - 辅助lambda的作用:lambda捕获外部的
p和val,对每个左值先执行断言判断:- 断言为
true时,完成赋值并返回true,继续处理下一个左值; - 断言为
false时直接返回false,触发短路逻辑,停止后续所有操作。
- 断言为
- 无需基例模板:当可变参数为空时,逻辑与的空折叠结果为
true,函数不会执行任何实际操作,因此不需要额外编写空参数的基例模板。 - dummy变量:用
[[maybe_unused]]标记变量来接收折叠表达式的结果,避免编译器因表达式无实际用途而发出警告。
这个实现完全替代了递归逻辑,同时完整保留了原有的短路更新行为。
内容的提问来源于stack exchange,提问作者ABu
相关产品推荐
相关产品推荐

