thecodex.expert · The Codex Family of Knowledge
C++

Coroutines

C++20 added the co_await, co_yield, and co_return keywords — but shipped almost no usable coroutine TYPES in the standard library to actually pair them with, a genuinely surprising gap most newcomers don’t expect.

C++20 / C++23 C++20 keywords, C++23 std::generator Last verified:
Canonical Definition

A coroutine is a function that can suspend its execution partway through (via co_await or co_yield) and resume later exactly where it left off, retaining its local state across the suspension. C++20 introduced this at the language level — the keywords and the underlying compiler transformation — but deliberately shipped no concrete, ready-to-use coroutine return types in the standard library itself, leaving that to be built by libraries or hand-written per project. std::generator, added in C++23, finally provides one standard, ready-to-use type specifically for the generator use case; other coroutine patterns (async tasks, for instance) still commonly rely on third-party libraries.

std::generator (C++23): the one ready-to-use standard coroutine type

co_yield suspends the coroutine and hands a value back to the caller, resuming from that exact point on the next iteration — the function's local state (i, in this case) is preserved across each suspension, just like Python's generators.

C++generator_example.cpp
#include <generator>   // C++23

std::generator<int> range(int start, int end) {
    for (int i = start; i < end; i++) {
        co_yield i;   // suspends here, hands i back, resumes from here next time
    }
}

int main() {
    for (int n : range(1, 5)) {
        std::cout << n << " ";   // 1 2 3 4
    }
}

Why C++20 alone wasn't enough to just "use coroutines"

Before C++23's std::generator, writing even a simple generator required hand-authoring an entire promise_type class implementing several required member functions — this genuine complexity is why most C++20-era coroutine adoption went through third-party libraries rather than raw language features directly.

C++the_gap.cpp
// A minimal hand-rolled coroutine return type needs, at minimum:
// - a nested promise_type
// - initial_suspend() / final_suspend()
// - return_void() or return_value()
// - yield_value() if using co_yield
// - unhandled_exception()
// — genuinely substantial boilerplate for even a simple generator, pre-C++23

co_await: the mechanism behind async code

co_await suspends the current coroutine until the awaited operation completes, without blocking the underlying thread — conceptually similar to await in JavaScript or Python, though C++'s standard library still provides no built-in async task type, leaving that role to libraries.

Sources

1
ISO/IEC 14882 (C++ Standard), "Coroutines" and "std::generator," cppreference.com/w/cpp/language/coroutines.