====Exemples==== ===co_yield=== Version Visual Studio : #include #include std::experimental::generator 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 #include #include namespace coro_exp { template class generator { public: struct promise_type; using handle_type = std::coroutine_handle; 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 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 #include std::future t() { return std::async([]() { std::cout << "I" << std::endl; return 1; }); } std::future 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=== [[https://ggulgulia.medium.com/painless-c-coroutines-part-1-ba90dd101adb|Painless C++ Coroutines-Part 1]] {{ :lang:cpp:coroutine:painless_c_coroutines_-part_1._learn_how_to_cretae_a_simple_coroutine_by_gajendra_gulgulia_may_2021_medium_medium_2023-02-25_11_53_43_.html |Archive du 31/05/2021 le 25/02/2023}} * Partie 4 #include #include //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 [[https://ggulgulia.medium.com/painless-coroutines-part2-29b36008b507|Painless C++ Coroutines-Part 2]] {{ :lang:cpp:coroutine:painless_c_coroutines-part_2._as_promised_i_continue_the_journey_of_by_gajendra_gulgulia_medium_2023-02-25_11_53_45_.html |Archive du 31/05/2021 le 25/02/2023}} #include #include #include #include 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::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 #include #include #include 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::from_promise(*this)}; } std::suspend_never initial_suspend() noexcept { 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{}; // 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 #include #include #include 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::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{}; // 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 #include #include #include 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::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 h_; ReturnObject(std::coroutine_handle 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 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 #include #include #include int ctr{0}; template // 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 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::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{}; 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(); } [[https://ggulgulia.medium.com/painless-c-coroutine-part-3-536e4bce4f4f|Painless C++ Coroutine-Part 3]] {{ :lang:cpp:coroutine:painless_c_coroutines-part_3._in_first_part_of_the_issue_painless_by_gajendra_gulgulia_medium_2023-02-25_11_53_46_.html |Archive du 31/05/2021 le 25/02/2023}} * Partie 7.1 #include #include #include #include #include // 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::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_; } }; // 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 #include #include #include int ctr{0}; template // 1 struct suspend_never { PromiseType* promise_{nullptr}; // 2.a bool await_ready() const noexcept { return false; } void await_suspend(std::coroutine_handle 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::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() { auto promise = co_await suspend_never{}; // 1, 2.d std::cout << promise->val_ << "\n"; } int main() { std::coroutine_handle<> h = foo(); h(); } * Partie 7.3 #include #include #include #include int ctr{0}; template // 1 struct suspend_never { PromiseType* promise_{nullptr}; // 2.a bool await_ready() const noexcept { return false; } void await_suspend(std::coroutine_handle 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::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() { auto promise = co_await suspend_never{}; // 1, 2.d std::cout << "From coroutine " << promise->val_ << "\n"; } int main() { std::coroutine_handle h = foo(); ReturnObject::promise_type prom = h.promise(); std::cout << "From main: " << prom.val_ << "\n"; h(); } * Partie 7.4 #include #include #include #include #include int ctr{0}; template struct suspend_never { PromiseType* promise_{nullptr}; bool await_ready() const noexcept { return false; } // bool await_suspend(std::coroutine_handle 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::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_; } }; 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{}; std::cout << ctr++ << ". Coroutine finished\n"; } int main() { std::coroutine_handle 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 #include #include #include int ctr{0}; template // 1 struct suspend_always { PromiseType* promise_{nullptr}; // 2.a bool await_ready() const noexcept { return false; } void await_suspend(std::coroutine_handle 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::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_; } }; using PromType = ReturnObject::promise_type; ReturnObject generator() { auto promise = co_await suspend_always{}; for (int i = 0;; i++) { promise->val_ = i; co_await std::suspend_always{}; } } int main() { std::coroutine_handle h = generator(); PromType& prom = h.promise(); for (int i = 0; i < 5; ++i) { std::cout << "From main: " << prom.val_ << "\n"; h(); } } OK : #include #include #include #include template struct suspend_never { PromiseType* promise_{nullptr}; bool await_ready() const noexcept { return false; } bool await_suspend(std::coroutine_handle 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::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_; } }; using PromType = ReturnObject::promise_type; ReturnObject generator() { auto promise = co_await suspend_never{}; for (int i = 0;; i++) { promise->val_ = i; co_await std::suspend_always{}; } } ReturnObject evenNumberGenerator() { auto promise = co_await suspend_never{}; for (int i = 0;; i = i + 2) { promise->val_ = i; co_await std::suspend_always{}; } } ReturnObject oddNumberGenerator() { auto promise = co_await suspend_never{}; for (int i = 1;; i = i + 2) { promise->val_ = i; co_await std::suspend_always{}; } } int main() { std::coroutine_handle h = generator(); PromType& prom = h.promise(); for (int i = 0; i < 5; ++i) { std::cout << "From main: " << prom.val_ << "\n"; h(); } } [[https://ggulgulia.medium.com/painless-c-coroutines-part-4-69117214bfdc|Painless C++ Coroutines-Part 4]] {{ :lang:cpp:coroutine:painless_c_coroutines-part_4._in_part_one_two_and_three_of_the_by_gajendra_gulgulia_medium_2023-02-25_11_53_48_.html |Archive du 13/06/2021 le 25/02/2023 }} * Partie 9 #include #include #include #include struct ReturnObject { struct promise_type { int val_; ReturnObject get_return_object() { return {std::coroutine_handle::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 h_; ReturnObject(std::coroutine_handle h) : h_{h} {} operator std::coroutine_handle() const { return h_; } }; using PromType = ReturnObject::promise_type; ReturnObject generator() { for (int i = 0;; i++) { co_yield i; } } int main() { std::coroutine_handle 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 #include #include #include template struct ReturnObject { struct promise_type { T val_; ReturnObject get_return_object() { return {std::coroutine_handle::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 h_; ReturnObject(std::coroutine_handle h) : h_{h} {} operator std::coroutine_handle() const { return h_; } }; using PromType = ReturnObject::promise_type; template ReturnObject generator() { for (int i = 0;; i++) { co_yield 1.234 + static_cast(i); } } int main() { std::coroutine_handle h = generator(); PromType& prom = h.promise(); for (int i = 0; i < 5; ++i) { std::cout << "From main: " << prom.val_ << "\n"; h(); } } [[https://ggulgulia.medium.com/painless-c-coroutines-part-5-f28e74c58a2c|Painless C++ Coroutines-Part 5]] {{ :lang:cpp:coroutine:painless_c_coroutines-part_5._in_the_fifth_issue_of_the_tutorial_by_gajendra_gulgulia_medium_2023-02-25_11_53_49_.html |Archive du 13/06/2021 le 25/02/2023}} * Partie 11.1 #include #include #include #include struct ReturnObject { struct promise_type { int val_{23}; ReturnObject get_return_object() { return {std::coroutine_handle::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 h_; ReturnObject(std::coroutine_handle h) : h_{h} {} operator std::coroutine_handle() const { return h_; } }; using PromType = ReturnObject::promise_type; ReturnObject foo() { co_return; } int main() { std::coroutine_handle h = foo(); std::cout << h.promise().val_ << "\n"; } * Partie 11.2 #include #include #include #include struct ReturnObject { struct promise_type { int val_; ReturnObject get_return_object() { return {std::coroutine_handle::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 h_; ReturnObject(std::coroutine_handle h) : h_{h} {} operator std::coroutine_handle() const { return h_; } }; using PromType = ReturnObject::promise_type; ReturnObject foo() { co_return 121; } int main() { std::coroutine_handle h = foo(); std::cout << h.promise().val_ << "\n"; } * Partie 12 #include #include #include #include struct ReturnObject { struct promise_type { int val_; ReturnObject get_return_object() { return {std::coroutine_handle::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 h_; ReturnObject(std::coroutine_handle h) : h_{h} {} operator std::coroutine_handle() const { return h_; } }; ReturnObject foo() { co_await std::suspend_never{}; } int main() { foo(); } #include #include #include #include struct ReturnObject { struct promise_type { int val_; ReturnObject get_return_object() { return {std::coroutine_handle::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 h_; ReturnObject(std::coroutine_handle h) : h_{h} {} operator std::coroutine_handle() const { return h_; } }; using PromType = ReturnObject::promise_type; ReturnObject foo() { co_await std::suspend_never{}; } int main() { std::coroutine_handle 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(); } }