Home > Back-end >  co_await is not supported in coroutines of type std::experimental::generator
co_await is not supported in coroutines of type std::experimental::generator

Time:05-16

What magic generator should I define to make the code below work?

#include <experimental/generator>

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

        co_yield i;
    }
};

with MSVC I get compiler error:

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

EDIT1:

The error goes from its 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);
        }

CodePudding user response:

My understanding is probably that generator_iterator can't handle co_await because it requires the task to be suspended with co_yeld, see the iterator source code:

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

            return *this;
        }

Probably some async_generator should handle a situation when a task is suspended with co_await and the return value is not ready yet, so its operator also suspends in its turn and becomes asynchronous like this:

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

where async_generator_increment_operation is defined as follows:

    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;
    }

CodePudding user response:

The stuff in any experimental folder is not part of C 20. In this case, this appears to be a part of some stuff for the coroutines TS version of co_await. However, the feature went through a lot of changes during standardization. So Microsoft is giving you a head's-up by giving you a very specific and informative error: you cannot use the C 20 feature with the types in that header (or probably any of the other "experimental" headers).

You'll have to either write your own generator type or use someone else's that is compatible with C 20 coroutines.

  • Related