====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();
}
}