我记得在某处读过 Eric Niebler 的引言:“协程使定义自己的范围变得微不足道”,这促使我尝试使用协程来实现众所周知的 views::concat
C++23 尚未采用。
由于目前没有编译器实现 std::generator
,我打算用著名的cppcoro图书馆代替。我的第一次尝试是使用折叠表达式直观地扩展 lambda(简化为仅支持 int
范围):
#include <ranges>
#include <cppcoro/generator.hpp>
template<ranges::input_range... Rs>
auto concat(Rs&&... rngs) -> cppcoro::generator<int>
{
([](auto& rng) -> cppcoro::generator<int> {
for (auto elem : rng)
co_yield elem;
}(rngs), ...);
}
不幸的是,这不是协程的工作原理,上面只是扩展了 lambda 和 discards the returned generator
.
我还尝试使用语法糖,例如 co_yield rngs...;
,但这显然不是有效的语法。
我的最终解决方案是创建一个协程 lambda,一次生成一个元素(可以在 C++23 中使用 ranges::elements_of
进行简化)。由于协程的返回值是一个generator
,所以我可以通过std::array
保存不同的generator
,然后应用 views::join
到此嵌套范围以连接其元素:
template<ranges::input_range... Rs>
auto concat(Rs&&... rngs) -> cppcoro::generator<int>
{
auto lambda = [](auto& rng) -> cppcoro::generator<int> {
for (auto elem : rng)
co_yield elem;
};
std::array nested_rng{lambda(rngs)...};
for (auto elem : nested_rng | views::join)
co_yield elem;
}
这对于我的测试用例( Demo )效果很好。
但是,这种方法需要额外使用 std::array
来存储不同的 generator
并依赖于 views::join
,不知道有没有更简洁高效的方法来实现?
最佳答案
你不需要数组(或 views::join
),一旦你有了 lambda,你就可以折叠它:
template<std::ranges::input_range... Rs>
auto concat(Rs&&... rs) -> std::generator<int&>
{
(co_yield std::ranges::elements_of(rs), ...);
}
在我们得到扩展语句之前,我不确定您是否可以做得更好。
Demo (使用 std::generator
链接到 P2502 的实现)。
注意generator<int&>
而不是generator<int>
因为在示例中我使用 vector<int>
,其引用类型为int&
...但是generator<int>
的引用类型是int&&
。尝试直接使用elements_of(rs)
不起作用,因为引用类型不可隐式转换。
关于c++ - 使用 C++ 协程实现views::concat?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76869401/