Outils pour utilisateurs

Outils du site


lang:cpp:coroutine

Ceci est une ancienne révision du document !


co_yield

Version Visual Studio :

#include <iostream>
#include <experimental/generator>
 
std::experimental::generator<int> loop(int iterations)
{
  for (int i = 0; i < iterations; i++)
  {
    co_yield i;
  }
}
 
int main()
{
  for (int i : loop(100))
  {
    std::cout << i << std::endl;
  }
}

Version gcc/clang :

#include <coroutine>
#include <memory>
#include <iostream>
 
namespace coro_exp {
 
  template<typename T>
  class generator {
   public:
    struct promise_type;
    using handle_type = std::coroutine_handle<promise_type>;
   private:
    handle_type coro;
   public:
    explicit generator(handle_type h) : coro(h) {}
    generator(const generator &) = delete;
    generator(generator &&oth) noexcept : coro(oth.coro) {
      oth.coro = nullptr;
    }
    generator &operator=(const generator &) = delete;
    generator &operator=(generator &&other) noexcept {
      coro = other.coro;
      other.coro = nullptr;
      return *this;
    }
    ~generator() {
      if (coro) {
        coro.destroy();
      }
    }
 
    bool next() {
      coro.resume();
      return not coro.done();
    }
 
    T getValue() {
      return coro.promise().current_value;
    }
 
    struct promise_type {
     private:
      T current_value{};
      friend class generator;
     public:
      promise_type() = default;
      ~promise_type() = default;
      promise_type(const promise_type&) = delete;
      promise_type(promise_type&&) = delete;
      promise_type &operator=(const promise_type&) = delete;
      promise_type &operator=(promise_type&&) = delete;
 
      auto initial_suspend() {
        return std::suspend_always{};
      }
 
      auto final_suspend() {
        return std::suspend_always{};
      }
 
      auto get_return_object() {
        return generator{handle_type::from_promise(*this)};
      }
 
      auto return_void() {
        return std::suspend_never{};
      }
 
      auto yield_value(T some_value) {
        current_value = some_value;
        return std::suspend_always{};
      }
 
      void unhandled_exception() {
        std::exit(1);
      }
    };
  };
 
} // coroutn_exp
 
using coro_exp::generator;
 
static constexpr int demo_ceiling = 100;
 
generator<int> loop(int iterations)
{
  for (int i = 0; i < iterations; i++)
  {
    co_yield i;
  }
}
 
 
int main() {
  auto iter = loop(demo_ceiling);
  while(iter.next()) {
    const auto value = iter.getValue();
    std::cout << value << '\n';
  }
}

co_return et co_await

#include <future>
#include <iostream>
 
std::future<int> t()
{
   return std::async([]() { std::cout << "I" << std::endl; return 1; });
}
 
std::future<void> foobar()
{
   std::cout << " First call !\n";
   std::cout << " Ret " << co_await t() << std::endl;
   std::cout << " Still first call !\n";
   std::cout << " Ret2 " << co_await t() << std::endl;
   std::cout << " Only after resumed !\n";
}
 
void tt()
{
   auto ttt = foobar();
   for (int i = 0; i < 10; i ++)
      std::cout << i << std::endl;
   for (int i = 0; i < 100; i++)
      std::this_thread::sleep_for(std::chrono::milliseconds(10));
   ttt.wait();
}
 
int main()
{
   tt();
}

Retour possible :

 First call !
 Ret I
0
1
2
1
 Still first call !
 Ret2 3
4
5
6
7
8
9
I
1
 Only after resumed !
lang/cpp/coroutine.1585232390.txt.gz · Dernière modification : 2020/03/26 15:19 de root