如何使用C++ ranges/std::views实现输入迭代器的分段消费?
可以用std::ranges/std::views实现相同功能
原代码通过手动操作输入迭代器完成了分段消费的逻辑,用C++20引入的std::ranges和std::views可以更简洁、声明式地实现完全一致的行为,同时保留输入迭代器的单次遍历特性。
对应实现代码
#include <ranges> #include <iostream> #include <numeric> void test(std::input_iterator auto it) { namespace rv = std::ranges::views; namespace rg = std::ranges; // 将输入迭代器包装为标准输入范围 auto rng = rv::subrange(it, std::default_sentinel); // 跳过所有小于1的元素,对应原代码的while循环 auto after_drop = rng | rv::drop_while([](int x) { return x < 1; }); // 提取第一个元素作为计数n,同时获取后续元素的范围 int n = *rg::begin(after_drop); auto rest_elements = after_drop | rv::drop(1); // 取n个元素,每个加1后求和,对应原代码的累加循环 int sum = rg::fold_left( rest_elements | rv::take(n) | rv::transform([](int x) { return x + 1; }), 0, std::plus<>() ); // 跳过前n个元素,将剩余元素除以2,取非零值直到遇到0,最后求积 int prd = rg::fold_left( rest_elements | rv::drop(n) | rv::transform([](int x) { return x / 2; }) | rv::take_while([](int x) { return x != 0; }), 1, std::multiplies<>() ); std::cout << sum << ' ' << prd << '\n'; } int main() { test(std::begin({0, 0, 0, 3, 400, 30, 2, 4, 6, 0})); }
代码与原逻辑的对应关系
rv::drop_while直接替代原代码中跳过小于1元素的while循环;- 通过
rg::begin(after_drop)获取第一个元素作为n,rv::drop(1)得到后续元素范围,对应原代码中取*it并递增迭代器的操作; rv::take(n) | rv::transform(...)配合rg::fold_left完成求和逻辑,和原代码中循环n次累加的结果完全一致;rv::drop(n)跳过已处理的n个元素后,用rv::transform执行除以2的操作,再通过rv::take_while过滤到0为止,最后用rg::fold_left求积,对应原代码中直到*it/2为0时停止的循环。
运行这段代码会得到和原代码完全相同的输出:435 6。
内容的提问来源于stack exchange,提问作者Abyx
相关产品推荐
相关产品推荐

