如何用C++协程实现views::concat?求更优实现方案
实现无依赖的cppcoro版views::concat
Eric Niebler曾说:“协程让自定义范围变得轻而易举”,受这句话启发,我尝试用C协程实现还未纳入C23标准的
views::concat。由于当前编译器不支持std::generator,我选择使用cppcoro库来实现。
踩过的坑
- 最初尝试用折叠表达式展开lambda,但返回的generator对象被直接丢弃,无法正确传递元素
- 尝试
co_yield rngs...的写法,编译器直接报错,这种语法本身不符合协程的yield规则
当前实现的不足
后来通过生成器lambda、std::array存储各个子生成器,再结合views::join实现了拼接功能,但该方案依赖std::array和views::join,不仅不够简洁,还带来了额外的容器存储开销。
优化后的实现
改用递归展开参数包的协程写法,完全摆脱对额外容器和视图的依赖:
#include <cppcoro/generator.hpp> #include <type_traits> // 处理单个或多个输入范围的核心实现 template<typename FirstRange, typename... RestRanges> cppcoro::generator<std::decay_t<typename FirstRange::value_type>> concat(FirstRange&& first, RestRanges&&... rest) { // 逐个yield第一个范围的所有元素 for (auto&& elem : std::forward<FirstRange>(first)) { co_yield std::forward<decltype(elem)>(elem); } // 递归处理剩余的范围 if constexpr (sizeof...(rest) > 0) { auto rest_gen = concat(std::forward<RestRanges>(rest)...); for (auto&& elem : rest_gen) { co_yield std::forward<decltype(elem)>(elem); } } } // 空参数重载(可选,避免无参数调用时编译错误) cppcoro::generator<void> concat() { co_return; }
实现优势
- 无额外依赖:不需要
std::array或views::join,仅依赖cppcoro库 - 惰性求值:元素按需生成,和标准库视图的行为一致,避免不必要的内存开销
- 完美转发:支持左值、右值等各种可迭代范围,保证元素和范围的生命周期正确
- 简洁高效:递归逻辑清晰,直接逐个转发元素,性能更接近原生迭代
内容的提问来源于stack exchange,提问作者康桓瑋
相关产品推荐
相关产品推荐

