cpp20 · advanced
C++20 Coroutines — co_yield, co_await, co_return
C++20 coroutines let you write functions that can suspend and resume. Any function containing co_yield, co_await, or co_return is a coroutine — the compiler transforms it, allocating a heap frame to preserve local variables and the current suspend point across resume calls. co_yield v suspends and passes v to the caller via promise_type::yield_value. co_await expr suspends until the awaitable is ready — the mechanism for zero-overhead async I/O. co_return completes the coroutine and destroys the frame. The caller holds a coroutine_handle<> and calls .resume() to continue execution. The return type must define a nested promise_type with: get_return_object, initial_suspend, final_suspend, yield_value, return_void/return_value, and unhandled_exception. Coroutines give you async/await and lazy generators with no OS thread overhead.
A C++20 coroutine is any function containing co_yield, co_await, or co_return; the compiler allocates a heap frame to hold locals and the suspend point; co_yield suspends and passes a value to the caller, co_await suspends until an awaitable is ready, co_return ends the coroutine and destroys the frame.
The code
// 1. A generator coroutine (lazily yields integers)Generator<int> range(int from, int to) { for (int i = from; i < to; ++i) co_yield i; // suspend, pass value to caller} // co_return implicit at end
// 2. promise_type protocol (boilerplate inside Generator<T>)struct promise_type { int current_value; auto yield_value(int v) { current_value = v; return suspend_always{}; } auto get_return_object() { return Generator{handle::from_promise(*this)}; } auto initial_suspend() { return suspend_always{}; } auto final_suspend() noexcept { return suspend_always{}; } void return_void() {} void unhandled_exception() { std::terminate(); }};
// 3. Caller sideauto gen = range(0, 3); // coroutine created, frame on heap, NOT runninggen.resume(); // runs until first co_yield → yields 0int v = gen.value(); // 0gen.resume(); // continues → yields 1v = gen.value(); // 1gen.resume(); // continues → co_return (done)
// 4. co_await — suspend until async result readyTask<int> fetchData() { int result = co_await asyncRead(); // suspend here co_return result + 1;}What this lesson walks through
- 01What is a C++20 coroutine?
- 02Caller invokes coroutine — frame allocated on heap, NOT running
- 03gen.resume() → runs until co_yield, yields value 0 to caller
- 04gen.resume() again → yields 1, then 2, then done
- 05co_return — coroutine completes, frame destroyed
- 06co_await — suspend until an async result is ready
- 07promise_type protocol — the glue the compiler uses
A coroutine is a function that can suspend its execution and be resumed later. Unlike threads, suspension is cooperative and zero-cost: no OS context switch. The C++20 keywords are co_yield (suspend + pass value), co_await (suspend until awaitable), and co_return (finish).
See it animated — step by step, at your own pace
Unlock the full interactive walkthrough of C++20 Coroutines — co_yield, co_await, co_return and 100+ animated C++ interview lessons.