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'; } }
#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 !
Painless C++ Coroutines-Part 1 Archive du 31/05/2021 le 25/02/2023
#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"; }
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() }
#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(); }
#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(); }
#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(); }
#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
#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(); }
#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(); }
#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(); }
#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"; }
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
#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; } }
#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
#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"; }
#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"; }
#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(); } }