如何使用匿名Lambda对多个Range执行统一处理?
解决方案:将匿名Lambda批量应用到多个Range
核心实现:可变参数模板版本
利用C++20的Range概念和可变参数折叠表达式,可以快速实现符合你需求的函数,代码简洁且完全基于标准库:
#include <ranges> #include <utility> // 依次将可调用对象应用到每个传入的Range template <std::ranges::input_range... Ranges, typename Callable> void for_each_range(Ranges&&... ranges, Callable&& func) { // 折叠表达式遍历每个Range,调用std::ranges::for_each (std::ranges::for_each(std::forward<Ranges>(ranges), std::forward<Callable>(func)), ...); }
使用示例
直接传递多个Range和末尾的匿名Lambda即可,支持修改Range元素:
#include <vector> #include <array> #include <iostream> int main() { std::vector<int> vec{1, 2, 3}; std::array<int, 3> arr{4, 5, 6}; int raw_arr[] = {7, 8, 9}; // 匿名多行Lambda,批量修改所有Range的元素 for_each_range(vec, arr, raw_arr, [](int& x) { x *= 2; std::cout << x << ' '; }); // 输出:2 4 6 8 10 12 14 16 18 }
为什么这个方案符合你的诉求
- Lambda位于参数末尾:完全对齐
std::ranges::for_each等标准算法的参数顺序,符合C++编程习惯 - 支持修改Range:通过完美转发(
std::forward)保留Range的可修改属性,避开了std::initializer_list的const限制 - 无需命名Lambda:直接传递匿名多行Lambda,不用为临时逻辑强行命名
- 类型安全:编译期检查每个Range是否满足input_range要求,Lambda是否能处理Range的元素类型,避免运行时错误
- 灵活兼容:支持不同类型的Range(vector、array、原生数组等)同时传入
标准库是否有现成方案
C++标准库目前没有直接提供这种“将同一可调用对象依次应用到多个独立Range”的算法,但上述实现完全基于标准库的std::ranges::for_each和可变参数模板特性,没有额外依赖,代码量极小,相当于对标准库功能的轻量封装。
关于std::views::zip的思路
std::views::zip的设计目标是并行遍历多个Range的对应位置元素(比如同时处理vec[0]、arr[0]、raw_arr[0]),和你需求的“对每个Range单独完整执行一遍Lambda”场景不匹配,因此确实不适用。
可选:支持初始化列表语法的版本(限同类型Range)
如果坚持想要{r1, r2, r3}的初始化列表语法,可以通过包装器绕开std::initializer_list的const限制,但该版本仅支持同类型的Range:
#include <ranges> #include <initializer_list> #include <utility> // 包装非const的Range引用 template <typename Range> struct RangeRef { Range& ref; explicit RangeRef(Range& r) : ref(r) {} }; // 辅助函数简化包装 template <typename Range> RangeRef<Range> wrap(Range& r) { return RangeRef<Range>(r); } // 接受初始化列表的版本 template <typename Range, typename Callable> void for_each_range(std::initializer_list<RangeRef<Range>> ranges, Callable&& func) { for (auto&& r : ranges) { std::ranges::for_each(r.ref, std::forward<Callable>(func)); } }
使用方式:
for_each_range({wrap(vec), wrap(arr), wrap(raw_arr)}, [](int& x) { x *= 2; });
内容的提问来源于stack exchange,提问作者Damir Tenishev
相关产品推荐
相关产品推荐

