co_await 在 std::experimental::generator 类型的协程中不受支持

co_await is not supported in coroutines of type std::experimental::generator

我应该定义什么魔法生成器才能使下面的代码工作?

#include <experimental/generator>

std::experimental::generator<int> generateInts()
{
    for (int i = 0; i < 10; ++i)
    {
        co_await some_async_func();

        co_yield i;
    }
};

使用 MSVC 我得到编译器错误:

error C2338: co_await is not supported in coroutines of type std::experimental::generator

编辑 1:

错误来自其 await_transform:

        template <class _Uty>
        _Uty&& await_transform(_Uty&& _Whatever) {
            static_assert(_Always_false<_Uty>,
                "co_await is not supported in coroutines of type std::experimental::generator");
            return _STD forward<_Uty>(_Whatever);
        }

任何 experimental 文件夹中的内容 不是 C++20 的一部分。在这种情况下,这似乎是 co_await 的协程 TS 版本的某些内容的一部分。但是,该功能在标准化过程中经历了 很多 的更改。因此,微软通过给你一个非常具体和信息丰富的错误来给你一个头's-up:你不能将 C++20 特性与该头文件中的类型一起使用(或者可能是任何其他“实验性”头文件) .

您必须编写自己的生成器类型或使用其他与 C++20 协程兼容的生成器类型。

我的理解大概是generator_iterator无法处理co_await,因为它需要用co_yeld暂停任务,看iterator源码:

        generator_iterator& operator++()
        {
            m_coroutine.resume();
            if (m_coroutine.done())
            {
                m_coroutine.promise().rethrow_if_exception();
            }

            return *this;
        }

可能某些 async_generator 应该处理任务被 co_await 挂起并且 return 值尚未准备好时的情况,因此它的 operator++ 也会挂起轮到它变得像这样异步:

        async_generator_increment_operation<T> operator++() noexcept
        {
            return async_generator_increment_operation<T>{ *this };
        }

其中async_generator_increment_operation定义如下:

    template<typename T>
    class async_generator_increment_operation final : public async_generator_advance_operation
    {
    public:

        async_generator_increment_operation(async_generator_iterator<T>& iterator) noexcept
            : async_generator_advance_operation(iterator.m_coroutine.promise(), iterator.m_coroutine)
            , m_iterator(iterator)
        {}

        async_generator_iterator<T>& await_resume();

    private:

        async_generator_iterator<T>& m_iterator;

    };

    template<typename T>
    async_generator_iterator<T>& async_generator_increment_operation<T>::await_resume()
    {
        if (m_promise->finished())
        {
            // Update iterator to end()
            m_iterator = async_generator_iterator<T>{ nullptr };
            m_promise->rethrow_if_unhandled_exception();
        }

        return m_iterator;
    }