c++ - 使用 C++ 协程实现views::concat?

标签 c++ std-ranges c++-coroutine c++23

我记得在某处读过 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/

相关文章:

c++ - 如何在 bleeding edge linux 上编译程序以在旧 linux 上运行

c++ - 随机访问迭代器 - 在 C++ 中执行 vector.end() - vector.begin() = vector.size();

c++ - 应该急切地还是懒惰地评估 C++ 约束?

c++ - 什么是 std::views::counted?

c++ - 传递给返回 awaitable 的函数的临时对象在使用 co_await 暂停点后是否仍然有效

c++ - Fortran 中 REAL(KIND=real_normal) 的 C 等效类型是什么?

c++ - std::ranges 如何与initializer_list 一起使用?

python - 通过C++ 20协程制作python生成器

c++ - Wininet 给出链接器错误我正在使用 devc++