• Class / Function / Type

      std::
    • Header file

      <>
    • Other / All

    最終更新日時(UTC):
    が更新

    履歴 編集

    function
    <coroutine>

    std::noop_coroutine

    noop_coroutine_handle noop_coroutine() noexcept;
    

    概要

    中断/再開時に何もしないコルーチンへのハンドルを取得する。

    「何もしないコルーチン」は、非対称コルーチン動作と対称コルーチン動作を実行時に制御するケースで利用される。

    戻り値

    中断/再開時に何もしないコルーチンへのハンドル

    例外

    投げない

    備考

    noop_coroutine()が返したハンドルと、別のnoop_coroutine()呼び出しで返されたハンドルとの等値性は規定されない。 (両者は等しいかもしれないし、等しくないかもしれない。)

    #include <coroutine>
    #include <iostream>
    #include <utility>
    
    struct task {
      struct promise_type {
        std::coroutine_handle<> next_;
        auto get_return_object() { return task{*this}; }
        auto initial_suspend() { return std::suspend_always{}; }
        auto final_suspend() noexcept { return std::suspend_always{}; }
        auto yield_value(bool cont)
        {
          struct awaiter {
            std::coroutine_handle<> next_;
            bool await_ready() { return false; }
            auto await_suspend(std::coroutine_handle<>) { return next_; }
            void await_resume() {}
          };
          // 継続条件condを満たす場合は次コルーチンnext_に制御を移し、
          // そうでない場合は再開元に制御を戻すAwaiterオブジェクトを返す。
          return awaiter{cont ? next_ : std::noop_coroutine()};
        }
        void return_void() {}
        void unhandled_exception() { std::terminate(); }
      };
    
      using coro_handle = std::coroutine_handle<promise_type>;
    
      ~task()
      {
        if (coro_)
          coro_.destroy();
      }
    
      task(task const&) = delete;
      task(task&& rhs)
        : coro_(std::exchange(rhs.coro_, nullptr)) {}
    
      void set_next(task& t)
      {
        coro_.promise().next_ = t.coro_;
      }
    
      void start()
      {
        if (!coro_.done())
          coro_.resume();
      }
    
    private:
      explicit task(promise_type& p)
        : coro_(coro_handle::from_promise(p)) {}
    
      coro_handle coro_;
    };
    
    task coro(int id)
    {
      int n = id * 10;
      for (;;) {
        std::cout << "coro#" << id << " " << n << std::endl;
        // 継続条件(0 < n)を満たす間はco_yield式により
        // 自コルーチンを中断して次のコルーチンを再開する。
        co_yield (0 < n);
        n /= 2;
      }
    }
    
    int main()
    {
      // コルーチン3個の巡回グラフ(c1→c2→c3→c1...)を構成する
      auto c1 = coro(1);
      auto c2 = coro(2);
      auto c3 = coro(3);
      c1.set_next(c2);
      c2.set_next(c3);
      c3.set_next(c1);
    
      // コルーチン動作を開始
      c1.start();
    }
    

    出力

    coro#1 10
    coro#2 20
    coro#3 30
    coro#1 5
    coro#2 10
    coro#3 15
    coro#1 2
    coro#2 5
    coro#3 7
    coro#1 1
    coro#2 2
    coro#3 3
    coro#1 0
    

    バージョン

    言語

    • C++20

    処理系

    関連項目

    参照