C++ Coroutines Cheat Sheet
co_await/co_yield/co_return keywords, promise_type machinery, and how to build a minimal generator or task type in C++20.
3 PagesAdvancedFeb 22, 2026
The Three Coroutine Keywords
Using any one of these in a function body makes it a coroutine.
- co_await expr- suspend until the awaited operation completes
- co_yield value- suspend and produce a value to the caller (generators)
- co_return value- complete the coroutine, optionally with a value
- promise_type- nested type on the return object that controls coroutine behavior
- coroutine_handle<Promise>- a handle used to resume/destroy a suspended coroutine
A Minimal Generator Type
Bare-metal generator using co_yield (C++20; std::generator exists in C++23's <generator>).
cpp
#include <coroutine>#include <optional>template <typename T>struct Generator { struct promise_type { T current_value; Generator get_return_object() { return Generator{ std::coroutine_handle<promise_type>::from_promise(*this) }; } std::suspend_always initial_suspend() { return {}; } std::suspend_always final_suspend() noexcept { return {}; } std::suspend_always yield_value(T value) { current_value = value; return {}; } void return_void() {} void unhandled_exception() { std::terminate(); } }; std::coroutine_handle<promise_type> handle; explicit Generator(std::coroutine_handle<promise_type> h) : handle(h) {} ~Generator() { if (handle) handle.destroy(); } bool next() { handle.resume(); return !handle.done(); } T value() { return handle.promise().current_value; }};Generator<int> counter(int start) { for (int i = start;; ++i) co_yield i;}
std::generator (C++23)
The standard library now ships a ready-made generator type in <generator>.
cpp
#include <generator>std::generator<int> range(int start, int end) { for (int i = start; i < end; ++i) { co_yield i; }}int sum = 0;for (int x : range(1, 11)) { sum += x; // sums 1..10, coroutine suspends/resumes each iteration}
A Minimal Awaitable Task
The essential shape of a co_await-able async task type.
cpp
template <typename T>struct Task { struct promise_type { T result; Task get_return_object() { return Task{ std::coroutine_handle<promise_type>::from_promise(*this) }; } std::suspend_never initial_suspend() { return {}; } std::suspend_always final_suspend() noexcept { return {}; } void return_value(T v) { result = v; } void unhandled_exception() { std::terminate(); } }; std::coroutine_handle<promise_type> handle; // Making Task itself awaitable bool await_ready() { return handle.done(); } void await_suspend(std::coroutine_handle<> caller) { /* schedule resumption */ } T await_resume() { return handle.promise().result; }};Task<int> compute() { co_return 42;}
Pro Tip
Writing coroutine machinery (promise_type, awaiters) by hand is a deep rabbit hole — for real async code prefer a battle-tested library (cppcoro, folly::coro, or Boost.Cobalt) and reserve hand-rolled promise types for learning or truly bespoke generator/task needs.
Was this cheat sheet helpful?
Explore Topics
#CCoroutines#CCoroutinesCheatSheet#Programming#Advanced#TheThreeCoroutineKeywords#AMinimalGeneratorType#StdGeneratorC23#AMinimalAwaitableTask#Concurrency#CheatSheet#SkillVeris