jjzjj

c++ - 如何用 C++20 协程说 Hello World?

coder 2024-02-24 原文

出于学习目的,我尝试使用 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 还没有准备好?

最佳答案

一些错误:

首先 - 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 .

关于c++ - 如何用 C++20 协程说 Hello World?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56185517/

有关c++ - 如何用 C++20 协程说 Hello World?的更多相关文章

  1. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  2. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  3. kvm虚拟机安装centos7基于ubuntu20.04系统 - 2

    需求:要创建虚拟机,就需要给他提供一个虚拟的磁盘,我们就在/opt目录下创建一个10G大小的raw格式的虚拟磁盘CentOS-7-x86_64.raw命令格式:qemu-imgcreate-f磁盘格式磁盘名称磁盘大小qemu-imgcreate-f磁盘格式-o?1.创建磁盘qemu-imgcreate-fraw/opt/CentOS-7-x86_64.raw10G执行效果#ls/opt/CentOS-7-x86_64.raw2.安装虚拟机使用virt-install命令,基于我们提供的系统镜像和虚拟磁盘来创建一个虚拟机,另外在创建虚拟机之前,提前打开vnc客户端,在创建虚拟机的时候,通过vnc

  4. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  5. ruby-on-rails - 如何用不同的用户运行nginx主进程 - 2

    A/ctohttp://wiki.nginx.org/CoreModule#usermaster进程曾经以root用户运行,是否可以以不同的用户运行nginxmaster进程? 最佳答案 只需以非root身份运行init脚本(即/etc/init.d/nginxstart),就可以用不同的用户运行nginxmaster进程。如果这真的是你想要做的,你将需要确保日志和pid目录(通常是/var/log/nginx&/var/run/nginx.pid)对该用户是可写的,并且您所有的listen调用都是针对大于1024的端口(因为绑定(

  6. arrays - Ruby 数组 += vs 推送 - 2

    我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“

  7. ruby - 如何用递增的值填充数组 Ruby - 2

    我正在尝试解决http://projecteuler.net/problem=1.我想创建一个方法,它接受一个整数,然后创建一个包含它前面的所有整数的数组,并将整数本身作为数组中的值。以下是我目前所拥有的。代码不起作用。defmake_array(num)numbers=Array.newnumcount=1numbers.eachdo|number|numbers 最佳答案 (1..num).to_a是您在Ruby中需要做的全部。1..num将创建一个Range对象,以1开始并以任意值num结束是。Range对象有to_a方法通过

  8. += 的 Ruby 方法 - 2

    有没有办法让Ruby能够做这样的事情?classPlane@moved=0@x=0defx+=(v)#thisiserror@x+=v@moved+=1enddefto_s"moved#{@moved}times,currentxis#{@x}"endendplane=Plane.newplane.x+=5plane.x+=10putsplane.to_s#moved2times,currentxis15 最佳答案 您不能在Ruby中覆盖复合赋值运算符。任务在内部处理。您应该覆盖+,而不是+=。plane.a+=b与plane.a=

  9. ruby - 如何用 Nokogiri 解析连续的标签? - 2

    我有这样的HTML代码:Label1Value1Label2Value2...我的代码不起作用。doc.css("first").eachdo|item|label=item.css("dt")value=item.css("dd")end显示所有首先标记,然后标记标签,我需要“标签:值” 最佳答案 首先,您的HTML应该有和中的元素:Label1Value1Label2Value2...但这不会改变您解析它的方式。你想找到s并遍历它们,然后在每个你可以使用next_element得到;像这样:doc=Nokogiri::HTML(

  10. ruby - Sinatra + Heroku + Datamapper 使用 dm-sqlite-adapter 部署问题 - 2

    出于某种原因,heroku尝试要求dm-sqlite-adapter,即使它应该在这里使用Postgres。请注意,这发生在我打开任何URL时-而不是在gitpush本身期间。我构建了一个默认的Facebook应用程序。gem文件:source:gemcuttergem"foreman"gem"sinatra"gem"mogli"gem"json"gem"httparty"gem"thin"gem"data_mapper"gem"heroku"group:productiondogem"pg"gem"dm-postgres-adapter"endgroup:development,:t

随机推荐