buzz() {
co_yield 42;
}
```
- type of `co_return` is not the same as the functions declared return type
- the declared return type allows access to the values passed to `co_return`
and `co_yield`, and it's often a template class that takes the type of
`co_return` and/or `co_yield` as a template parameter
---
# Coroutine implemented as functions
- mathematical equivalence of functions and coroutines (duality)
- but the function mechanics uses hardware support such as assembly instruction
`CALL` knows to save the current address on the stack, increment the stack
pointer register and continue from the location provided
- in practice a coroutine is reduce to functions to exploit this hardware
efficiency
- the first of these functions is special: ramp
- the following resume or destroy from a previous suspension
---
# Ramp
---
# Determine promise type
```cpp
// given
task foo() {
co_await bar();
}
```
```cpp
class task {
public:
using promise_type = some_other_type;
};
// or
class task {
public:
class promise_type {
};
};
```
- this promise type has nothing to do with `std::promise`
- usually promise type associated to the coroutine via the declared return type
- in the simplest: the `promise_type` type (literally) aliased or defined
within the declared return type
---
# Coroutine traits
```cpp
template
struct coroutine_traits {};
template
requires requires { typename R::promise_type; }
struct coroutine_traits
{
using promise_type = typename R::promise_type;
};
```
- this customization point allows using coroutine declared return types that do
not need to be change to expose a `promise_type` OR to consider coroutine
function arguments too in the resolution to the `promise_type`
---
# Body re-write
```cpp
promise_type promise(<>);
try {
co_await promise.initial_suspend();
// ... body here
}
catch (...) {
if (!made enough progress through initial_suspend) {
throw;
}
promise.undhandled_exception();
}
co_await promise.final_suspend();
```
- above pseudocode is a over-simplification
- promise is allocated on the coroutine frame
- it allows coroutine behaviour customization:
- should it suspend at the start?
- should it suspend at the end?
- what should it do if exceptions are thrown?
- space on the frame to handle the values from `co_return` and/or `co_yield`
- etc.
---
TODO:
- constructing a promise
- how state is stored
- two options
- conversion between promise and coroutine_handle
- at constant offset
- get_return_object
- customizing awaiters
- temporary awaiters are stored on the coroutine frame
- the purpose of await suspend after coroutine is suspended
- the three versions of await_suspend
- the tail recursion case
---
# Questions?