task<int> f(); task<void> g1() { int i = co_await f(); std::cout << "f() => " << i << std::endl; } template <typename... Args> task<void> g2(Args&&...) { // OK, ellipsis is a pack expansion int i = co_await f(); std::cout << "f() => " << i << std::endl; } task<void> g3(int a, ...) { // error: variable parameter list not allowed int i = co_await f(); std::cout << "f() => " << i << std::endl; }— end example
{ promise-type promise promise-constructor-arguments ; try { co_await promise.initial_suspend() ; function-body } catch ( ... ) { if (!initial-await-resume-called) throw ; promise.unhandled_exception() ; } final-suspend : co_await promise.final_suspend() ; }where
#include <iostream> #include <coroutine> // ::operator new(size_t, nothrow_t) will be used if allocation is needed struct generator { struct promise_type; using handle = std::coroutine_handle<promise_type>; struct promise_type { int current_value; static auto get_return_object_on_allocation_failure() { return generator{nullptr}; } auto get_return_object() { return generator{handle::from_promise(*this)}; } auto initial_suspend() { return std::suspend_always{}; } auto final_suspend() { return std::suspend_always{}; } void unhandled_exception() { std::terminate(); } void return_void() {} auto yield_value(int value) { current_value = value; return std::suspend_always{}; } }; bool move_next() { return coro ? (coro.resume(), !coro.done()) : false; } int current_value() { return coro.promise().current_value; } generator(generator const&) = delete; generator(generator && rhs) : coro(rhs.coro) { rhs.coro = nullptr; } ~generator() { if (coro) coro.destroy(); } private: generator(handle h) : coro(h) {} handle coro; }; generator f() { co_yield 1; co_yield 2; } int main() { auto g = f(); while (g.move_next()) std::cout << g.current_value() << std::endl; }— end example