In C++20, a promise type is a compiler-mandated interface that defines the state management, control flow, and communication mechanics of a coroutine. It acts as the low-level bridge between the coroutine’s internal execution state (the coroutine frame) and the caller, dictating how the coroutine initializes, suspends, yields, returns, and handles exceptions. When the compiler encounters a coroutine (a function containingDocumentation Index
Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt
Use this file to discover all available pages before exploring further.
co_await, co_yield, or co_return), it determines the promise type by inspecting the coroutine’s return type T and its parameter types Args... via std::coroutine_traits<T, Args...>. By default, the compiler looks for a nested type named T::promise_type, but this mechanism allows the promise type to be specialized based on the arguments passed to the coroutine.
The Promise Type Interface
To satisfy the compiler’s coroutine state machine, a promise type must implement a specific set of methods. Below is the structural syntax of a fully defined promise type:Mechanical Breakdown of Required Methods
The compiler injects calls to the promise type’s methods at deterministic points within the coroutine’s lifecycle:get_return_object(): Invoked after the coroutine frame is allocated, the coroutine parameters are copied or moved into the frame, and the promise object itself is constructed. The compiler calls this method with no arguments on the newly constructed promise object to construct the object returned to the caller. The method simply needs to return an instance of the coroutine’s return type. While it is common for types that control the coroutine to create astd::coroutine_handlehere and pass it to the return object’s constructor, it is not a C++ requirement; fire-and-forget coroutines, for example, do not need to expose a handle.initial_suspend(): Invoked immediately afterget_return_object(). It returns an awaitable type (likestd::suspend_alwaysorstd::suspend_never). If it suspends, control returns to the caller before the coroutine body executes.final_suspend(): Invoked when the coroutine body finishes execution (either via completion or an unhandled exception). The C++ standard dictates that the expressionpromise.final_suspend()must be non-throwing, which is why the method itself must be markednoexcept. It returns an awaitable object. Suspending here keeps the coroutine frame alive, allowing the caller to extract final values or inspect the state before manually destroying the frame.return_void()orreturn_value(T): Invoked when the compiler evaluates aco_returnstatement or reaches the end of the coroutine body. The C++ standard dictates that a promise type must not implement both. However, a promise type can implement neither if the coroutine never terminates (e.g., an infinite generator that never evaluates aco_returnand never reaches the end of its body).unhandled_exception(): Invoked if an exception escapes the coroutine body. The implementation typically captures the exception usingstd::current_exception()to store it in the promise state for later rethrowing.
Mechanical Breakdown of Optional Methods
yield_value(T): Invoked when the compiler evaluates aco_yieldexpression. It takes the yielded value, stores it in the promise state, and returns an awaitable to dictate whether the coroutine suspends after yielding.await_transform(T): If defined, the compiler intercepts everyco_awaitexpression and transforms it by callingpromise.await_transform(expression). This allows the promise type to restrict or modify what types can be awaited within the coroutine.operator new/operator delete: By default, the compiler dynamically allocates the coroutine frame on the heap. However, C++20 permits Coroutine Allocation Elision (often called HALO - Heap Allocation Elision Optimization). The compiler is explicitly permitted to elide the dynamic heap allocation and place the coroutine state on the stack if it can prove the frame’s lifetime is strictly nested within the caller. If heap allocation is required and not elided, overloading these operators on the promise type overrides the default global allocator for that specific coroutine, allowing for custom memory pools or specialized allocation strategies.
Master C++ with Deep Grasping Methodology!Learn More





