C++20coreadvanced
co_await (C++20 Addition)
C++20 · The Big Four · Compiler flag: -std=c++20
Explanation
Suspends a coroutine until an awaited operation completes.
Real-World Scenario
Wait for an async I/O operation in a network server.
Quick Snippet
snippet.cpp
#include <coroutine> auto task() { co_await std::suspend_always{}; }Full Example
co_await.cpp
// CodeNebula - C++20 Example: co_await with a Simple Awaitable
// Compile: g++ -std=c++20 -Wall -Wextra -o example co_await.cpp
// co_await suspends a coroutine until an awaitable object is ready.
// An awaitable must provide: await_ready(), await_suspend(), await_resume().
#include <iostream>
#include <coroutine>
// --- Task type: a coroutine that co_awaits and produces a result ---
struct Task {
struct promise_type {
int result = 0;
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(int v) { result = v; }
void unhandled_exception() { std::terminate(); }
};
std::coroutine_handle<promise_type> handle;
explicit Task(std::coroutine_handle<promise_type> h) : handle(h) {}
~Task() { if (handle) handle.destroy(); }
Task(const Task&) = delete;
Task(Task&& o) noexcept : handle(o.handle) { o.handle = nullptr; }
Task& operator=(const Task&) = delete;
int result() const { return handle.promise().result; }
};
// --- Custom awaitable: simulates an async computation ---
struct ComputeAwaitable {
int input;
int computed_result = 0;
// await_ready: return true if result is already available (no suspend)
bool await_ready() const noexcept {
std::cout << " await_ready() called — checking if ready\n";
return false; // not ready, must suspend
}
// await_suspend: called when the coroutine suspends
void await_suspend(std::coroutine_handle<> h) noexcept {
std::cout << " await_suspend() called — computing result\n";
computed_result = input * input + 1; // simulate async work
h.resume(); // resume immediately (in real code, a scheduler would do this)
}
// await_resume: return the result when the coroutine resumes
int await_resume() const noexcept {
std::cout << " await_resume() called — returning " << computed_result << "\n";
return computed_result;
}
};
// A coroutine that uses co_await
Task compute_and_add(int a, int b) {
std::cout << "Awaiting computation for " << a << "...\n";
int result_a = co_await ComputeAwaitable{a};
std::cout << "Awaiting computation for " << b << "...\n";
int result_b = co_await ComputeAwaitable{b};
std::cout << "Both computations done.\n";
co_return result_a + result_b;
}
// Demonstrate co_await with std::suspend_always / std::suspend_never
Task trivial_awaits() {
std::cout << "\nTrivial awaits:\n";
co_await std::suspend_never{}; // does not suspend
std::cout << " After suspend_never — no suspension occurred\n";
co_return 42;
}
int main() {
std::cout << "=== co_await with Custom Awaitable ===\n\n";
auto task1 = compute_and_add(3, 5);
std::cout << "Final result: " << task1.result() << "\n";
// 3*3+1 = 10, 5*5+1 = 26, sum = 36
auto task2 = trivial_awaits();
std::cout << "Trivial result: " << task2.result() << "\n";
return 0;
}
// Expected output:
// === co_await with Custom Awaitable ===
//
// Awaiting computation for 3...
// await_ready() called — checking if ready
// await_suspend() called — computing result
// await_resume() called — returning 10
// Awaiting computation for 5...
// await_ready() called — checking if ready
// await_suspend() called — computing result
// await_resume() called — returning 26
// Both computations done.
// Final result: 36
//
// Trivial awaits:
// After suspend_never — no suspension occurred
// Trivial result: 42
Run command
g++ -std=c++20 -Wall -Wextra -o example co_await.cpp