【问题标题】:How to say Hello World with C++20 coroutine?如何用 C++20 协程说 Hello World?
【发布时间】:2019-10-04 17:35:45
【问题描述】:

仅出于学习目的,我尝试使用 C++20 协程制作过于复杂的“Hello World”程序:

HelloWorldMessage sayHelloToWorld()
{
    co_yield "Hello";
    co_yield " ";
    co_yield "World";
    co_yield "!";
}

int main() 
{
    for (auto w : sayHelloToWorld())
    {
        std::cout << w;
    }
}

为了准备这样的HelloWorldMessage生成器,我主要基于最新的clang警告消息和uncomplete cppreference page和这个example

所以我的结果如下。这里缺少什么?因为,我没有说你好,而是遇到了分段错误:

link:

struct HelloWorldState
{
    const char* currentWord = "<not value yet>";
    bool finalWord = false;
};

struct HelloWorldPromise
{
    HelloWorldState state;
    std::experimental::suspend_always initial_suspend() const noexcept { return {}; }
    std::experimental::suspend_always final_suspend() const noexcept { return {}; }

    std::experimental::suspend_always yield_value(const char* word) noexcept
    {
        state.currentWord = word;
        return {};
    }  

    std::experimental::suspend_always return_void() noexcept
    {
        state.finalWord = true;
        return {};
    }  

    auto& get_return_object() noexcept
    {
        return *this;
    }

    void unhandled_exception()
    {
        state.finalWord = true;
        throw;
    }
};

struct HelloWorldMessage
{
    using promise_type = HelloWorldPromise;
    using promise_handle = std::experimental::coroutine_handle<promise_type>;

    struct Iter
    {
        promise_handle handle = nullptr;
        HelloWorldState state;

        using iterator_category = std::input_iterator_tag;
        using value_type        = const char*;
        using difference_type   = ptrdiff_t;
        using pointer           = value_type const *;
        using reference         = value_type const &;

        reference operator * () const { assert(handle); return state.currentWord; }
        pointer operator -> () const { return std::addressof(operator*()); }

        bool operator == (const Iter& other) { return handle == other.handle; }
        bool operator != (const Iter& other) { return !(*this == other); }

        Iter() = default;
        Iter(promise_handle handle)
            : handle(handle)
        {
           assert(handle);
           next();
        }

        Iter& operator ++()
        {
            if (!handle)
                return *this;
            if (state.finalWord)
            {
                handle = nullptr;
                return *this;
            }
            next();
            return *this;
        }

        void next()
        {
            try {
                handle.resume();
                state = handle.promise().state;
            } catch (...) {
                std::cerr << "@%$#@%#@$% \n";
            }
        }

    };

    promise_handle handle = nullptr;
    HelloWorldMessage(promise_type& promise) : handle(promise_handle::from_promise(promise)) {}

    Iter begin() const { assert(handle); return {handle}; }
    Iter end() const { return {}; }
};

也许clang还没有准备好?

【问题讨论】:

    标签: c++ generator c++20 c++-coroutine


    【解决方案1】:

    几个错误:

    首先——promise 应该返回生成器对象,而不是对自身的引用。所以正确的做法是:

    struct HelloWorldPromise
    {
        ...
        auto get_return_object();
        ...        
    };
    
    struct HelloWorldMessage
    {
        ...
    };
    
    auto HelloWorldPromise::get_return_object()
    {
        return HelloWorldMessage(*this);
    }
    

    下一步 - 终止和返回 void 可以简化为:

    void return_void() noexcept
    {}  
    void unhandled_exception()
    {
        std::terminate();
    }
    

    接下来 - 在迭代器中 - 我们将依赖 handle.done - 所以不需要 state.finalWord。完整的迭代器来源是:

    struct Iter
    {
        promise_handle handle = nullptr;
        HelloWorldState state;
    
        reference operator * () const { return state.currentWord; }
        pointer operator -> () const { return std::addressof(operator*()); }
    
        bool operator == (const Iter& other) const { return !handle == !other.handle; }
        bool operator != (const Iter& other) const { return !(*this == other); }
    
        Iter() = default;
        Iter(promise_handle handle)
            : handle(handle)
        {
           next();
        }
    
        Iter& operator ++()
        {
            if (!handle)
                return *this;
            next();
            return *this;
        }
    
        void next()
        {
            if (!handle)
                return;
            try {
                handle.resume();
                if (!handle.done())
                   state = handle.promise().state;
                else {
                    handle = nullptr;
                }
            } catch (...) {
                std::cerr << "@%$#@%#@$% \n";
            }
        }
    
    };
    

    以及完整的工作示例here

    我的大部分更正来自2018/n4736.pdf

    【讨论】:

    • 完整的工作示例现在不起作用。你必须#include &lt;cassert&gt;。此外,还有一个警告可以通过删除HelloWorldMessage::Iter::operator== 的定义来消除(这需要编辑operator!= 的定义)。
    • @JohnFreeman 谢谢,已修复。运算符 == 和 != 没有 const 说明符。
    猜你喜欢
    • 1970-01-01
    • 2012-08-18
    • 1970-01-01
    • 1970-01-01
    • 2023-04-09
    • 2013-02-23
    • 1970-01-01
    • 2021-07-21
    • 2022-01-22
    相关资源
    最近更新 更多