> ## Documentation Index
> Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt
> Use this file to discover all available pages before exploring further.

# C++ Co-await

The `co_await` operator is a unary operator introduced in C++20 that suspends the execution of a coroutine, yields control back to its caller or resumer, and defines the resumption point once the awaited operation completes. It acts as the primary state-machine transition mechanism within the C++ coroutine architecture.

```cpp theme={"dark"}
co_await expression;
```

## Language Restrictions

The `co_await` operator is subject to strict language restrictions. It cannot be used in the following contexts:

* The `main` function (which cannot be a coroutine).
* Default arguments.
* Constructors or destructors.
* Catch blocks of a function-try-block.
* The initializer of a block-scope variable with `static` or `thread_local` storage duration.
* Functions declared as `constexpr` or `consteval`.
* Plain functions (the presence of `co_await` is what transforms a function into a coroutine).

## The Awaitable to Awaiter Transformation

When the compiler encounters `co_await expression`, it does not execute a simple function call. Instead, it resolves the *Awaitable* (`expression`) into an *Awaiter* object, which dictates the exact suspension and resumption behavior. The resolution follows a strict pipeline:

1. **Promise Transformation:** The compiler checks the current coroutine's promise type for the `await_transform` member. If the promise type declares *any* `await_transform` member, name lookup succeeds, and the compiler exclusively attempts to use it. The result of `promise.await_transform(expression)` becomes the new awaitable. If no overload matches the specific expression, it results in a hard compile error; it does *not* fall back to the original expression. The original expression is used directly only if `await_transform` is not declared at all in the promise type.
2. **Operator Overload:** The compiler then searches for `operator co_await` applied to the awaitable from step 1. This follows standard C++ operator overloading rules. The compiler considers both member `operator co_await` functions and non-member `operator co_await` functions (found via Argument-Dependent Lookup) simultaneously. Standard overload resolution selects the best match. If an operator is found and successfully applied, its return value becomes the Awaiter.
3. **Fallback:** If no `operator co_await` is found, the awaitable resulting from step 1 is treated directly as the Awaiter.

## The Awaiter Interface

Once the Awaiter object is resolved, the compiler expects it to implement three specific methods: `await_ready`, `await_suspend`, and `await_resume`. The evaluation of `co_await` is mechanically expanded into the following pseudo-code, demonstrating how control flow depends on the return type of `await_suspend`:

```cpp theme={"dark"}
{
    auto&& awaiter = get_awaiter(expression);
    
    if (!awaiter.await_ready()) {
        // 1. Suspend the coroutine (save instruction pointer, registers, local state to the heap frame)
        <suspend_coroutine> 
        
        try {
            // 'Promise' is the promise type of the current coroutine.
            // 'p' is the current coroutine's instantiated promise object.
            auto handle = std::coroutine_handle<Promise>::from_promise(p);
            using ResultT = decltype(awaiter.await_suspend(handle));
            
            // 2. Execute await_suspend and determine control flow based on its return type
            if constexpr (std::is_void_v<ResultT>) {
                awaiter.await_suspend(handle);
                <yield_to_caller_or_resumer>
            } else if constexpr (std::is_same_v<ResultT, bool>) {
                if (awaiter.await_suspend(handle)) {
                    <yield_to_caller_or_resumer>
                } else {
                    <abort_suspension_and_immediately_resume>
                }
            } else {
                // Returns std::coroutine_handle<Z>
                auto target_handle = awaiter.await_suspend(handle);
                <symmetric_transfer_to_target_handle(target_handle)>
            }
        } catch (...) {
            // If await_suspend throws, suspension is aborted, state is restored,
            // and the exception propagates immediately.
            <abort_suspension_and_restore_state>
            throw;
        }
        
        // 3. Resumption point (reached when coroutine_handle::resume() is called)
        <resume_point>
    }
    
    // 4. The co_await expression evaluates to the result of await_resume().
    // This value is yielded to the surrounding expression.
    awaiter.await_resume();
}
```

## Mechanics of `await_suspend`

The most critical phase of the `co_await` evaluation occurs during `await_suspend`. The return type of this method dictates the immediate control flow after the coroutine's state has been saved:

* **`void`**: The coroutine remains suspended, and control is unconditionally returned to the current caller or resumer.
* **`bool`**: If it returns `true`, control is returned to the caller. If it returns `false`, the suspension is aborted, and the current coroutine is immediately resumed. Because the coroutine is *already* suspended when `await_suspend` is called (its state has been saved to the heap frame), returning `false` is typically used for operations that complete concurrently during the suspension process (e.g., a failed compare-and-swap), requiring the suspension to be aborted and the coroutine to continue execution.
* **`std::coroutine_handle<Z>`**: The current coroutine remains suspended, and execution is symmetrically transferred to the returned coroutine handle. This enables efficient tail-calls between coroutines without consuming additional stack frames.

## Exception Handling Mechanics

The `co_await` expansion guarantees precise exception propagation depending on which part of the Awaiter interface throws:

* **If `await_ready` throws:** The exception propagates immediately into the surrounding coroutine body. The coroutine is never suspended.
* **If `await_suspend` throws:** The coroutine's suspension is aborted, the coroutine is immediately resumed (state restored), and the exception is propagated out of the `co_await` expression. This guarantees that the coroutine state machine does not leak a suspended state if the suspension logic fails.
* **If `await_resume` throws:** The exception propagates normally into the surrounding coroutine body. This occurs either after the coroutine has been successfully resumed, or immediately if `await_ready` returned `true` and bypassed suspension.

## Standard Trivial Awaiters

The `<coroutine>` header provides two fundamental, empty awaiter types used to control basic suspension mechanics, often utilized within promise types:

```cpp theme={"dark"}
// Never suspends. await_ready() returns true.
co_await std::suspend_never{}; 

// Always suspends. await_ready() returns false.
co_await std::suspend_always{}; 
```

<div
  style={{ 
display: "flex", 
justifyContent: "space-between", 
alignItems: "center", 
maxWidth: "754px", 
padding: "1rem 0",
marginBottom: "24px"
}}
>
  <span style={{ fontWeight: "bold", fontSize: "1.25rem", color: "var(--tw-prose-headings)", fontFamily: "Inter, ui-sans-serif, system-ui, sans-serif" }}>Tired of Poor C++ Skills? Fix That With Deep Grasping!</span>

  <a
    href="https://syntblaze.com"
    target="_blank"
    style={{ 
  marginLeft: "24px",
  textDecoration: "none", 
  backgroundColor: "#007AFF",
  color: "#ffffff", 
  padding: "6px 16px", 
  borderRadius: "16px",
  fontSize: "0.9rem",
  fontWeight: "600",
  textAlign: "center",
  transition: "background-color 0.2s ease"
}}
  >
    Learn More
  </a>
</div>

<div style={{ display: "flex", gap: "12px", flexWrap: "wrap" }}>
  <img src="https://mintcdn.com/syntblazellc/-L0ums_2lctDSZ1l/images/skill-tracking.png?fit=max&auto=format&n=-L0ums_2lctDSZ1l&q=85&s=b9b0305c93bb501c9e767b5c76c88835" style={{ width: "30%", minWidth: 60 }} width="621" height="1344" data-path="images/skill-tracking.png" />

  <img src="https://mintcdn.com/syntblazellc/23tyuOzaWS88qFlc/images/nuggets.png?fit=max&auto=format&n=23tyuOzaWS88qFlc&q=85&s=c86c80197299762989e9b882419b2109" style={{ width: "30%", minWidth: 60 }} width="621" height="1344" data-path="images/nuggets.png" />

  <img src="https://mintcdn.com/syntblazellc/-L0ums_2lctDSZ1l/images/bite-sized-exercises.png?fit=max&auto=format&n=-L0ums_2lctDSZ1l&q=85&s=a65f9a38c37ff28ab73ed783c53c60e3" style={{ width: "30%", minWidth: 60 }} width="621" height="1344" data-path="images/bite-sized-exercises.png" />
</div>

<div style={{ display: "flex", gap: "12px", flexWrap: "wrap", marginTop: "12px" }}>
  <img src="https://mintcdn.com/syntblazellc/-L0ums_2lctDSZ1l/images/mastery-chain.png?fit=max&auto=format&n=-L0ums_2lctDSZ1l&q=85&s=748a1763454713e679260fbb95f154a2" style={{ width: "30%", minWidth: 60 }} width="621" height="1344" data-path="images/mastery-chain.png" />

  <img src="https://mintcdn.com/syntblazellc/-L0ums_2lctDSZ1l/images/element-previews.png?fit=max&auto=format&n=-L0ums_2lctDSZ1l&q=85&s=242f61448ff5dd6deaaab2dccc13b507" style={{ width: "30%", minWidth: 60 }} width="621" height="1344" data-path="images/element-previews.png" />

  <img src="https://mintcdn.com/syntblazellc/-L0ums_2lctDSZ1l/images/element-explanations.png?fit=max&auto=format&n=-L0ums_2lctDSZ1l&q=85&s=cf0fc1c31f9cd0fc26716781be05fbc9" style={{ width: "30%", minWidth: 60 }} width="621" height="1344" data-path="images/element-explanations.png" />
</div>
