In first part of the issue, Painless C++ Coroutine Part-1, the we laid out all the components that are needed to instantiate a compilable coroutine.

In the second part of the issue, Painless C++ Coroutine Part-2, the demonstrations continued to explain the technique to resume a suspended coroutine by understanding the coroutine handle and its relation with the promise type object. Following this, the huge but important detour was taken to understand awaiter and awaitable objects by creating the custom awaiters.

I continue the journey to finally reveal how to return the data to the caller of the coroutine in section 7 and finally a lazy generator using coroutine in section 8.

7. Returning data from coroutines to caller

This is the exciting part where all the coroutine customization can be used in one place, but it has to be broken down to assimilatable and incremental chunks to manage the complexity. These incremental chunks are divided in three parts:

  1. **Connecting the coroutine awaiter and the **foo
  2. Connecting the coroutine promise_type and the foo via awaiter.

and finally

3.** Connecting foo to main.**

7.1. Connecting the coroutine awaiter and the foo

At the conclusion of section 6.1, it was mentioned that the return type of expression co_await expr is same as that of awaiter::await_resume which till this point has been void. Fortunately standard doesn’t place any restriction on what the return type of await_resume should be and one can return anything from it and catch the returned data as a result of the evaluation of co_await expr expression and the returned value can be used within the coroutine. The example below (note the usage of a custom suspend_never awaiter object):

struct suspend_never{
    ...
    double await_resume() const noexcept {return 10.234;}
};
ReturnObject foo(){
    double val = co_await suspend_never{};
    std::cout << val << "\n"; 
}
int main()
{
    std::coroutine_handle<> h =  foo();
}
//stdout: 10.234

The working code can be found here.

One can try to persist the value val returned by co_await suspend_never{} expression over multiple suspend-resume of coroutine by returning pointer or reference from suspend_never::await_resumebut since the operand suspend_never{} to co_await is a temporary, every time the coroutine is resumed, the suspend_never::val_ is destroyed along with the temporary object.

#modern-cpp #cpp20 #coroutine #cxx #c++

Painless C++ Coroutine-Part 3
1.80 GEEK