CodeNebula
C++20coreadvanced

co_yield (C++20 Addition)

C++20 · The Big Four · Compiler flag: -std=c++20

Explanation

Yields a value from a coroutine, suspending execution.

Real-World Scenario

Generate a sequence of game events incrementally.

Quick Snippet

snippet.cpp
#include <coroutine> auto gen() { co_yield 42; }

Full Example

co_yield.cpp
// CodeNebula - C++20 Example: co_yield with Generator Pattern
// Compile: g++ -std=c++20 -Wall -Wextra -o example co_yield.cpp

// co_yield suspends a coroutine and produces a value to the caller.
// This enables lazy generation of sequences — values are computed
// on demand, one at a time, without storing the entire sequence.

#include <iostream>
#include <coroutine>
#include <cstdint>

// A reusable Generator<T> type
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(); }
    Generator(const Generator&) = delete;
    Generator(Generator&& o) noexcept : handle(o.handle) { o.handle = nullptr; }
    Generator& operator=(const Generator&) = delete;

    bool next() {
        handle.resume();
        return !handle.done();
    }
    T value() const { return handle.promise().current_value; }
};

// Generator: range of integers
Generator<int> range(int start, int end, int step = 1) {
    for (int i = start; i < end; i += step) {
        co_yield i;
    }
}

// Generator: infinite sequence of powers of two
Generator<std::uint64_t> powers_of_two() {
    std::uint64_t val = 1;
    while (true) {
        co_yield val;
        val *= 2;
    }
}

// Generator: string tokens (character by character)
Generator<char> vowels() {
    for (char c : {'a', 'e', 'i', 'o', 'u'}) {
        co_yield c;
    }
}

// Generator: triangular numbers (1, 3, 6, 10, 15, ...)
Generator<int> triangular_numbers() {
    int sum = 0;
    for (int n = 1; ; ++n) {
        sum += n;
        co_yield sum;
    }
}

int main() {
    std::cout << "=== co_yield Generator Pattern ===\n\n";

    // Range generator
    std::cout << "range(0, 10, 2): ";
    auto r = range(0, 10, 2);
    while (r.next()) std::cout << r.value() << " ";
    std::cout << "\n";

    // Powers of two (take first 10)
    std::cout << "powers_of_two (first 10): ";
    auto p = powers_of_two();
    for (int i = 0; i < 10 && p.next(); ++i)
        std::cout << p.value() << " ";
    std::cout << "\n";

    // Vowels
    std::cout << "vowels: ";
    auto v = vowels();
    while (v.next()) std::cout << v.value() << " ";
    std::cout << "\n";

    // Triangular numbers (first 7)
    std::cout << "triangular (first 7): ";
    auto t = triangular_numbers();
    for (int i = 0; i < 7 && t.next(); ++i)
        std::cout << t.value() << " ";
    std::cout << "\n";

    return 0;
}

// Expected output:
// === co_yield Generator Pattern ===
//
// range(0, 10, 2): 0 2 4 6 8
// powers_of_two (first 10): 1 2 4 8 16 32 64 128 256 512
// vowels: a e i o u
// triangular (first 7): 1 3 6 10 15 21 28
Run command
g++ -std=c++20 -Wall -Wextra -o example co_yield.cpp