C++20中如何模拟std::views::zip同时消费两个std::ranges?
C++20下替代std::views::zip的优雅方案
最优方案:用std::views::zip_transform直接完成配对+构造
C++20标准里其实提供了更贴合你需求的工具——std::views::zip_transform,它可以直接对多个范围的对应元素执行变换,完全不需要先zip再transform,代码更简洁:
namespace views = std::views; std::vector<int> a0{1,2,3,4}; std::vector<int> b0{6,7,8,9}; auto a = a0 | views::transform(foo); // foo和bar为自定义函数 auto b = b0 | views::transform(bar); // 直接将两个范围的对应元素传入lambda构造Object auto objects = views::zip_transform( [](auto&& elem_a, auto&& elem_b) { return Object{std::forward<decltype(elem_a)>(elem_a), std::forward<decltype(elem_b)>(elem_b)}; }, a, b );
zip_transform会自动遍历两个范围的对应位置元素,直到其中一个范围耗尽,完美替代你原本想用zip+transform实现的逻辑。
手动迭代配对方案(不推荐,仅作备选)
如果因为某些原因不想用zip_transform,可以手动用迭代器遍历两个范围,生成视图:
namespace ranges = std::ranges; namespace views = std::views; std::vector<int> a0{1,2,3,4}; std::vector<int> b0{6,7,8,9}; auto a = a0 | views::transform(foo); auto b = b0 | views::transform(bar); // 生成配对视图的lambda auto make_objects_view = [&]() { auto it_a = ranges::begin(a); auto it_b = ranges::begin(b); const auto min_size = std::min(ranges::size(a), ranges::size(b)); return views::generate([=, &a, &b]() mutable -> Object { auto obj = Object{*it_a, *it_b}; ++it_a; ++it_b; return obj; }) | views::take(min_size); }; auto objects = make_objects_view();
这个方法需要手动处理迭代器递增和范围长度边界,不如zip_transform简洁,仅作为特殊场景下的备选。
关于你尝试的iota_view方案
你之前用iota_view配合std::get的思路行不通,因为std::get<>()的索引参数必须是编译期常量,而iota_view生成的i是运行时变量,编译器无法通过。
内容的提问来源于stack exchange,提问作者Jonah F
相关产品推荐
相关产品推荐

