Outils pour utilisateurs

Outils du site


lang:cpp:coroutine

Exemples

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 !

Tutorial

Gajendra Gulgulia

Painless C++ Coroutines-Part 1 Archive du 31/05/2021 le 25/02/2023

  • Partie 4
#include <coroutine>
#include <iostream>
 
//global counter
int num{0};
 
struct ReturnObject{
  struct promise_type{
 
    promise_type(){std::cout <<  num++ << ". promise_type default ctor\n";}
 
    ReturnObject get_return_object() { 
        std::cout <<  num++ << ". promise_type::get_return_object\n";
        return {}; 
    }
 
    std::suspend_never initial_suspend() {
         std::cout <<  num++ << ". promise_type::initial_suspend\n";
         return {}; 
    }
 
    std::suspend_never final_suspend() noexcept{ 
        std::cout <<  num++ << ". promise_type::final_suspend\n";
        return {};
    }
 
    void unhandled_exception(){std::cout <<  num++ << ".throw\n";}
  };
};
 
ReturnObject foo(){
 
    std::cout <<  num++ << ".  hello from coroutine1\n";
    co_await std::suspend_never{}; //never suspend the coroutine at this point
    co_await std::suspend_never{}; //never suspend the coroutine at this point
    co_await std::suspend_always{}; //suspend the coroutine at this point
    std::cout <<  num++ << ".  hello from coroutine2\n";   
} 
 
int main(){foo();
        std::cout <<  num++ << ". END\n";
}
  • Partie 5

Painless C++ Coroutines-Part 2 Archive du 31/05/2021 le 25/02/2023

#include <concepts>
#include <coroutine>
#include <exception>
#include <iostream>
 
static int ctr{0};
 
struct ReturnObject {
    struct promise_type {
        ReturnObject get_return_object() {
            // call ctor of ReturnObject with the coroutine handle
            return {
                std::coroutine_handle<promise_type>::from_promise(*this)};  // A
        }
        std::suspend_never initial_suspend() { return {}; }
        std::suspend_never final_suspend() noexcept { return {}; }
        void unhandled_exception() {}
    };
 
    // B.3 implicit conversion operator
    operator std::coroutine_handle<>() const { return h_; }
 
   private:
    std::coroutine_handle<> h_;  // B.1: member variable
 
    ReturnObject(std::coroutine_handle<> h) : h_{h} {}  // B.2: ctor
};
 
// coroutine
ReturnObject foo() {
    std::cout << ++ctr << ". hello from coroutine 1\n";
    co_await std::suspend_always{};  // suspend the coroutine at this point
    std::cout << ++ctr << ". hello from coroutine 2\n";
    co_await std::suspend_always{};  // suspend the coroutine at this point
    std::cout << ++ctr << ". hello from coroutine 3\n";
}
 
// main
int main() {
    std::coroutine_handle<> h = foo();
    std::cout << ++ctr << ". resuming coroutine from main 1\n";
    h();
    std::cout << ++ctr << ". resuming coroutine from main 2\n";
    h.resume();  // same as h()
}
  • Partie 6.2
#include <concepts>
#include <coroutine>
#include <exception>
#include <iostream>
 
int ctr{0};
 
struct suspend_always {
    bool await_ready() const noexcept {
        std::cout << ++ctr << ". suspend_always::await_ready\n";
        return false;
    }
    void await_suspend(std::coroutine_handle<> h) const noexcept {
        std::cout << ++ctr << ". suspend_always::await_suspend\n";
    }
    void await_resume() const noexcept {
        std::cout << ++ctr << ". suspend_always::await_resume\n";
    }
};
 
// ReturnObject same as in section 5
struct ReturnObject {
    struct promise_type {
        unsigned value_{0};
        ReturnObject get_return_object() {
            return {std::coroutine_handle<promise_type>::from_promise(*this)};
        }
        std::suspend_never initial_suspend() noexcept { return {}; }
        std::suspend_never final_suspend() noexcept { return {}; }
        void unhandled_exception() {}
    };
 
    std::coroutine_handle<promise_type> h_;
    ReturnObject(std::coroutine_handle<promise_type> h) : h_{h} {}
    operator std::coroutine_handle<>() const { return h_; }
};
 
ReturnObject foo() {
    std::cout << ++ctr << ". first hello from coroutine\n";
 
    co_await suspend_always{};  // evaluate custom awaiter
 
    std::cout << ++ctr << ". second hello from coroutine\n";
}
 
int main() {
    std::coroutine_handle<> h = foo();
    std::cout << ++ctr << ". main\n";
    h();
}
  • Partie 6.3
#include <concepts>
#include <coroutine>
#include <exception>
#include <iostream>
 
int ctr{0};
 
struct suspend_always {
    bool await_ready() const noexcept {
        std::cout << ++ctr << ". suspend_always::await_ready\n";
        return false;
    }
 
    bool await_suspend(std::coroutine_handle<> h) const noexcept {
        std::cout << ++ctr << ". suspend_always::await_suspend\n";
        return true;  // Change it.
    }
    void await_resume() const noexcept {
        std::cout << ++ctr << ". suspend_always::await_resume\n";
    }
};
 
struct ReturnObject {
    struct promise_type {
        unsigned value_{0};
        ReturnObject get_return_object() {
            return {std::coroutine_handle<promise_type>::from_promise(*this)};
        }
        std::suspend_never initial_suspend() { return {}; }
        std::suspend_never final_suspend() noexcept { return {}; }
        void unhandled_exception() {}
    };
 
    std::coroutine_handle<promise_type> h_;
    ReturnObject(std::coroutine_handle<promise_type> h) : h_{h} {}
    operator std::coroutine_handle<>() const { return h_; }
};
 
ReturnObject foo() {
    std::cout << ++ctr << ". first hello from coroutine\n";
    co_await suspend_always{};  // evaluate custom awaiter
    std::cout << ++ctr << ". second hello from coroutine\n";
    co_await std::suspend_always{};
    std::cout << ++ctr << ". third hello from coroutine\n";
}
 
int main() { std::coroutine_handle<> h = foo(); }
  • Partie 6.4
#include <concepts>
#include <coroutine>
#include <exception>
#include <iostream>
 
int ctr{0};
 
// ReturnObject same as in section 5
struct ReturnObject {
    struct promise_type {
        unsigned value_{0};
        ReturnObject get_return_object() {
            return {std::coroutine_handle<promise_type>::from_promise(*this)};
        }
        std::suspend_never initial_suspend() {
            std::cout << ++ctr << ". promise_type::initial_suspend\n";
            return {};
        }
        std::suspend_never final_suspend() noexcept { return {}; }
        void unhandled_exception() {}
    };
 
    std::coroutine_handle<promise_type> h_;
    ReturnObject(std::coroutine_handle<promise_type> h) : h_{h} {}
    operator std::coroutine_handle<>() const { return h_; }
};
 
struct suspend_always {
    bool await_ready() const noexcept {
        std::cout << ++ctr << ". suspend_always::await_ready\n";
        return false;
    }
    void await_suspend(
        std::coroutine_handle<ReturnObject::promise_type> h) const noexcept {
        std::cout << ++ctr << ". suspend_always::await_suspend\n";
    }
    void await_resume() const noexcept {
        std::cout << ++ctr << ". suspend_always::await_resume\n";
    }
};
 
ReturnObject foo() {
    std::cout << ++ctr << ". first hello from coroutine\n";
 
    co_await suspend_always{};  // evaluate custom awaiter
 
    std::cout << ++ctr << ". second hello from coroutine\n";
}
 
int main() {
    std::coroutine_handle<> h = foo();
    std::cout << ++ctr << ". resuming coroutinefrom main\n";
    h();
}
  • Partie 6.5
#include <concepts>
#include <coroutine>
#include <exception>
#include <iostream>
 
int ctr{0};
 
template <typename PromiseType = void>  // note this
struct suspend_always {
    bool await_ready() const noexcept {
        std::cout << ++ctr << ". suspend_always::await_ready\n";
        return false;
    }
    /*********** and this **********/
    void await_suspend(std::coroutine_handle<PromiseType> h) const noexcept {
        std::cout << ++ctr << ". suspend_always::await_suspend\n";
    }
    void await_resume() const noexcept {
        std::cout << ++ctr << ". suspend_always::await_resume\n";
    }
};
 
// same as in section 5
struct ReturnObject {
    struct promise_type {
        unsigned value_{0};
        ReturnObject get_return_object() {
            return {std::coroutine_handle<promise_type>::from_promise(*this)};
        }
        std::suspend_never initial_suspend() { return {}; }
        std::suspend_never final_suspend() noexcept { return {}; }
        void unhandled_exception() {}
    };
 
    std::coroutine_handle<> h_;
    ReturnObject(std::coroutine_handle<> h) : h_{h} {}
    operator std::coroutine_handle<>() const { return h_; }
};
 
ReturnObject foo() {
    std::cout << ++ctr << ". first hello from coroutine\n";
    co_await suspend_always<>{};  // note this
    co_await suspend_always<ReturnObject::promise_type>{};
    std::cout << ++ctr << ". second hello from coroutine\n";
}
 
int main() {
    std::coroutine_handle<> h = foo();
    std::cout << ++ctr << ". resuming coroutine from main 1\n";
    h();
    std::cout << ++ctr << ". resuming coroutine from main 2\n";
    h();
}

Painless C++ Coroutine-Part 3 Archive du 31/05/2021 le 25/02/2023

  • Partie 7.1
#include <concepts>
#include <coroutine>
#include <exception>
#include <iostream>
#include <memory>
 
// custom suspend_never
struct suspend_never {
    double* val_{new double(10.234)};
    bool await_ready() const noexcept { return true; }
    void await_suspend(std::coroutine_handle<> h) const noexcept {}
    double* await_resume() const noexcept { return val_; }
};
 
// ReturnObject
struct ReturnObject {
    struct promise_type {
        unsigned value_{0};
        ReturnObject get_return_object() {
            return {std::coroutine_handle<promise_type>::from_promise(*this)};
        }
        std::suspend_never initial_suspend() { return {}; }
        std::suspend_never final_suspend() noexcept { return {}; }
        void unhandled_exception() {}
    };
 
    std::coroutine_handle<promise_type> h_;
    ReturnObject(std::coroutine_handle<promise_type> h) : h_{h} {}
    operator std::coroutine_handle<>() const { return h_; }
};
 
// coroutine
ReturnObject foo() {
    // temporary suspend_never is destroyed after evaluation
    auto val1 = co_await suspend_never{};
    std::cout << *val1 << "\n";  //(1)
 
    *val1 = 20.234;
    delete val1;
 
    auto val2 = co_await suspend_never{};
    std::cout << *val2 << "\n";  //(2) == (1)
    delete val2;
}
 
// main
int main() { std::coroutine_handle<> h = foo(); }
  • Partie 7.2
#include <concepts>
#include <coroutine>
#include <exception>
#include <iostream>
 
int ctr{0};
 
template <typename PromiseType = void>  // 1
struct suspend_never {
    PromiseType* promise_{nullptr};  // 2.a
    bool await_ready() const noexcept { return false; }
 
    void await_suspend(std::coroutine_handle<PromiseType> h) noexcept {
        promise_ = &h.promise();  // 2.b
    }
 
    PromiseType* await_resume() const noexcept { return promise_; }  // 2.c
};
 
struct ReturnObject {
    struct promise_type {
        int val_{11}; /*<---------------------- Note this  */
        ReturnObject get_return_object() {
            return {std::coroutine_handle<promise_type>::from_promise(*this)};
        }
        std::suspend_never initial_suspend() { return {}; }
        std::suspend_never final_suspend() noexcept { return {}; }
        void unhandled_exception() {}
    };
 
    std::coroutine_handle<promise_type> h_;
    ReturnObject(std::coroutine_handle<promise_type> h) : h_{h} {}
    operator std::coroutine_handle<>() const { return h_; }
};
 
ReturnObject foo() {
    auto promise =
        co_await suspend_never<ReturnObject::promise_type>{};  // 1, 2.d
    std::cout << promise->val_ << "\n";
}
 
int main() {
    std::coroutine_handle<> h = foo();
    h();
}
  • Partie 7.3
#include <concepts>
#include <coroutine>
#include <exception>
#include <iostream>
 
int ctr{0};
 
template <typename PromiseType = void>  // 1
struct suspend_never {
    PromiseType* promise_{nullptr};  // 2.a
    bool await_ready() const noexcept { return false; }
 
    void await_suspend(std::coroutine_handle<PromiseType> h) noexcept {
        promise_ = &h.promise();  // 2.b
    }
 
    PromiseType* await_resume() const noexcept { return promise_; }  // 2.c
};
 
struct ReturnObject {
    struct promise_type {
        int val_{11}; /*<------------- Note this  */
        ReturnObject get_return_object() {
            return {std::coroutine_handle<promise_type>::from_promise(*this)};
        }
        std::suspend_never initial_suspend() { return {}; }
        std::suspend_never final_suspend() noexcept { return {}; }
        void unhandled_exception() {}
    };
 
    std::coroutine_handle<promise_type> h_;
    ReturnObject(std::coroutine_handle<promise_type> h) : h_{h} {}
    operator std::coroutine_handle<promise_type>() const { return h_; }
};
 
ReturnObject foo() {
    auto promise =
        co_await suspend_never<ReturnObject::promise_type>{};  // 1, 2.d
    std::cout << "From coroutine " << promise->val_ << "\n";
}
 
int main() {
    std::coroutine_handle<ReturnObject::promise_type> h = foo();
    ReturnObject::promise_type prom = h.promise();
    std::cout << "From main: " << prom.val_ << "\n";
    h();
}
  • Partie 7.4
#include <concepts>
#include <coroutine>
#include <exception>
#include <iostream>
#include <thread>
 
int ctr{0};
template <typename PromiseType = void>
struct suspend_never {
    PromiseType* promise_{nullptr};
    bool await_ready() const noexcept { return false; }  //
 
    bool await_suspend(std::coroutine_handle<PromiseType> h) noexcept {
        promise_ = &h.promise();
 
        std::cout << ctr++ << ". In suspend_always::await_suspend\n"
                  << "   Do further processing on promise_->_val = "
                  << promise_->val_ << " ... \n";
 
        return false;
    }
 
    PromiseType* await_resume() const noexcept { return promise_; }
};
 
struct ReturnObject {
    struct promise_type {
        int val_;
        ReturnObject get_return_object() {
            return {std::coroutine_handle<promise_type>::from_promise(*this)};
        }
        std::suspend_never initial_suspend() { return {}; }
        std::suspend_never final_suspend() noexcept { return {}; }
        void unhandled_exception() {}
    };
 
    std::coroutine_handle<promise_type> h_;
    ReturnObject(std::coroutine_handle<promise_type> h) : h_{h} {}
    operator std::coroutine_handle<promise_type>() const { return h_; }
};
 
using PromType = ReturnObject::promise_type;
 
ReturnObject foo() {
    std::cout
        << ctr++
        << ". Suspending the coroutine for 1st time with trivial awaitable\n";
    co_await std::suspend_always{};
 
    std::cout
        << ctr++
        << ". Suspending the coroutine for 2nd time with custom awaitable\n";
    auto promise = co_await suspend_never<PromType>{};
    std::cout << ctr++ << ". Coroutine finished\n";
}
 
int main() {
    std::coroutine_handle<PromType> h = foo();
    PromType* prom = &h.promise();
 
    std::cout << ctr++
              << ". From main: current value of promise_->val_: " << prom->val_
              << "\n";  // access promise.val_ in main
    std::cout << ctr++
              << ". Changing  promise_->val_ in main and resuming coroutine\n";
 
    prom->val_ = 21;
    h();
 
    std::cout << ctr++ << ". main finished\n";
}
  • Partie 8

KO :

#include <concepts>
#include <coroutine>
#include <exception>
#include <iostream>
 
int ctr{0};
 
template <typename PromiseType = void>  // 1
struct suspend_always {
    PromiseType* promise_{nullptr};  // 2.a
    bool await_ready() const noexcept { return false; }
 
    void await_suspend(std::coroutine_handle<PromiseType> h) noexcept {
        promise_ = &h.promise();  // 2.b
    }
 
    PromiseType* await_resume() const noexcept { return promise_; }  // 2.c
};
 
struct ReturnObject {
    struct promise_type {
        int val_; /*<---------------------------------------------- Note this */
        ReturnObject get_return_object() {
            return {std::coroutine_handle<promise_type>::from_promise(*this)};
        }
        std::suspend_never initial_suspend() { return {}; }
        std::suspend_never final_suspend() noexcept { return {}; }
        void unhandled_exception() {}
    };
 
    std::coroutine_handle<promise_type> h_;
    ReturnObject(std::coroutine_handle<promise_type> h) : h_{h} {}
    operator std::coroutine_handle<promise_type>() const { return h_; }
};
 
using PromType = ReturnObject::promise_type;
ReturnObject generator() {
    auto promise = co_await suspend_always<PromType>{};
    for (int i = 0;; i++) {
        promise->val_ = i;
        co_await std::suspend_always{};
    }
}
 
int main() {
    std::coroutine_handle<PromType> h = generator();
    PromType& prom = h.promise();
    for (int i = 0; i < 5; ++i) {
        std::cout << "From main: " << prom.val_ << "\n";
        h();
    }
}

OK :

#include <concepts>
#include <coroutine>
#include <exception>
#include <iostream>
 
template <typename PromiseType = void>
struct suspend_never {
    PromiseType* promise_{nullptr};
    bool await_ready() const noexcept { return false; }
 
    bool await_suspend(std::coroutine_handle<PromiseType> h) noexcept {
        promise_ = &h.promise();
        return false;
    }
 
    PromiseType* await_resume() const noexcept { return promise_; }
};
 
struct ReturnObject {
    struct promise_type {
        int val_;
        ReturnObject get_return_object() {
            return {std::coroutine_handle<promise_type>::from_promise(*this)};
        }
        std::suspend_never initial_suspend() { return {}; }
        std::suspend_never final_suspend() noexcept { return {}; }
        void unhandled_exception() {}
    };
 
    std::coroutine_handle<promise_type> h_;
    ReturnObject(std::coroutine_handle<promise_type> h) : h_{h} {}
    operator std::coroutine_handle<promise_type>() const { return h_; }
};
 
using PromType = ReturnObject::promise_type;
 
ReturnObject generator() {
    auto promise = co_await suspend_never<PromType>{};
    for (int i = 0;; i++) {
        promise->val_ = i;
        co_await std::suspend_always{};
    }
}
 
ReturnObject evenNumberGenerator() {
    auto promise = co_await suspend_never<PromType>{};
    for (int i = 0;; i = i + 2) {
        promise->val_ = i;
        co_await std::suspend_always{};
    }
}
 
ReturnObject oddNumberGenerator() {
    auto promise = co_await suspend_never<PromType>{};
    for (int i = 1;; i = i + 2) {
        promise->val_ = i;
        co_await std::suspend_always{};
    }
}
 
int main() {
    std::coroutine_handle<PromType> h = generator();
    PromType& prom = h.promise();
    for (int i = 0; i < 5; ++i) {
        std::cout << "From main: " << prom.val_ << "\n";
        h();
    }
}

Painless C++ Coroutines-Part 4 Archive du 13/06/2021 le 25/02/2023

  • Partie 9
#include <concepts>
#include <coroutine>
#include <exception>
#include <iostream>
 
struct ReturnObject {
    struct promise_type {
        int val_;
        ReturnObject get_return_object() {
            return {std::coroutine_handle<promise_type>::from_promise(*this)};
        }
        std::suspend_never initial_suspend() noexcept { return {}; }
        std::suspend_never final_suspend() noexcept { return {}; }
        std::suspend_always yield_value(int value) {
            val_ = value;
            return {};
        }
        void unhandled_exception() {}
    };
 
    std::coroutine_handle<promise_type> h_;
    ReturnObject(std::coroutine_handle<promise_type> h) : h_{h} {}
    operator std::coroutine_handle<promise_type>() const { return h_; }
};
 
using PromType = ReturnObject::promise_type;
 
ReturnObject generator() {
    for (int i = 0;; i++) {
        co_yield i;
    }
}
 
int main() {
    std::coroutine_handle<PromType> h = generator();
    PromType& prom = h.promise();
    for (int i = 0; i < 5; ++i) {
        std::cout << "From main: " << prom.val_ << "\n";
        h();
    }
}
 
ReturnObject evenNumberGenerator() {
    for (int i = 0;; i = i + 2) {
        co_yield i;
    }
}
 
ReturnObject oddNumberGenerator() {
    for (int i = 1;; i = i + 2) {
        co_yield i;
    }
}
  • Partie 10
#include <concepts>
#include <coroutine>
#include <exception>
#include <iostream>
 
template <typename T>
struct ReturnObject {
    struct promise_type {
        T val_;
        ReturnObject get_return_object() {
            return {std::coroutine_handle<promise_type>::from_promise(*this)};
        }
        std::suspend_never initial_suspend() noexcept { return {}; }
        std::suspend_never final_suspend() noexcept { return {}; }
        std::suspend_always yield_value(T value) {
            val_ = value;
            return {};
        }
        void unhandled_exception() {}
    };
 
    std::coroutine_handle<promise_type> h_;
    ReturnObject(std::coroutine_handle<promise_type> h) : h_{h} {}
    operator std::coroutine_handle<promise_type>() const { return h_; }
};
 
using PromType = ReturnObject<float>::promise_type;
 
template <typename T>
ReturnObject<T> generator() {
    for (int i = 0;; i++) {
        co_yield 1.234 + static_cast<T>(i);
    }
}
 
int main() {
    std::coroutine_handle<PromType> h = generator<float>();
    PromType& prom = h.promise();
    for (int i = 0; i < 5; ++i) {
        std::cout << "From main: " << prom.val_ << "\n";
        h();
    }
}

Painless C++ Coroutines-Part 5 Archive du 13/06/2021 le 25/02/2023

  • Partie 11.1
#include <concepts>
#include <coroutine>
#include <exception>
#include <iostream>
 
struct ReturnObject {
    struct promise_type {
        int val_{23};
        ReturnObject get_return_object() {
            return {std::coroutine_handle<promise_type>::from_promise(*this)};
        }
        std::suspend_never initial_suspend() noexcept { return {}; }
        std::suspend_never final_suspend() noexcept { return {}; }
        void unhandled_exception() {}
        void return_void() {}
    };
 
    std::coroutine_handle<promise_type> h_;
    ReturnObject(std::coroutine_handle<promise_type> h) : h_{h} {}
    operator std::coroutine_handle<promise_type>() const { return h_; }
};
 
using PromType = ReturnObject::promise_type;
 
ReturnObject foo() { co_return; }
 
int main() {
    std::coroutine_handle<PromType> h = foo();
    std::cout << h.promise().val_ << "\n";
}
  • Partie 11.2
#include <concepts>
#include <coroutine>
#include <exception>
#include <iostream>
 
struct ReturnObject {
    struct promise_type {
        int val_;
        ReturnObject get_return_object() {
            return {std::coroutine_handle<promise_type>::from_promise(*this)};
        }
        std::suspend_never initial_suspend() noexcept { return {}; }
        std::suspend_never final_suspend() noexcept { return {}; }
        void unhandled_exception() {}
        void return_value(int val) { val_ = val; }
    };
 
    std::coroutine_handle<promise_type> h_;
    ReturnObject(std::coroutine_handle<promise_type> h) : h_{h} {}
    operator std::coroutine_handle<promise_type>() const { return h_; }
};
 
using PromType = ReturnObject::promise_type;
 
ReturnObject foo() { co_return 121; }
 
int main() {
    std::coroutine_handle<PromType> h = foo();
    std::cout << h.promise().val_ << "\n";
}
  • Partie 12
#include <concepts>
#include <coroutine>
#include <exception>
#include <iostream>
 
struct ReturnObject {
    struct promise_type {
        int val_;
        ReturnObject get_return_object() {
            return {std::coroutine_handle<promise_type>::from_promise(*this)};
        }
        std::suspend_never initial_suspend() noexcept { return {}; }
        void return_void() { std::cout << "called return_void\n"; }
        std::suspend_always final_suspend() noexcept { return {}; }
        void unhandled_exception() {}
    };
 
    std::coroutine_handle<promise_type> h_;
    ReturnObject(std::coroutine_handle<promise_type> h) : h_{h} {}
    operator std::coroutine_handle<promise_type>() const { return h_; }
};
 
ReturnObject foo() { co_await std::suspend_never{}; }
int main() { foo(); }
#include <concepts>
#include <coroutine>
#include <exception>
#include <iostream>
 
struct ReturnObject {
    struct promise_type {
        int val_;
        ReturnObject get_return_object() {
            return {std::coroutine_handle<promise_type>::from_promise(*this)};
        }
        std::suspend_never initial_suspend() noexcept { return {}; }
 
        std::suspend_always final_suspend() noexcept {
            std::cout << "suspending coroutine for one last time\n";
            return {};
        }
        void unhandled_exception() {}
 
        void return_void() { std::cout << "return_void\n"; }
    };
 
    std::coroutine_handle<promise_type> h_;
    ReturnObject(std::coroutine_handle<promise_type> h) : h_{h} {}
    operator std::coroutine_handle<promise_type>() const { return h_; }
};
 
using PromType = ReturnObject::promise_type;
 
ReturnObject foo() { co_await std::suspend_never{}; }
 
int main() {
    std::coroutine_handle<PromType> h = foo();
    PromType* prom = &h.promise();
    /*
     call h.resume() many times
    */
    if (h.done()) {
        /*
          do something with prom one last time
        */
        std::cout << "done execution of coroutine\n";
        h.destroy();
    }
}
lang/cpp/coroutine.txt · Dernière modification : 2023/04/27 05:05 de root