0Pricing
C++ Academy · レッスン

シンプルなジェネレーターの実装

値を遅延的に生成するジェネレーターコルーチンを構築します。

「シンプルなジェネレーターの実装」はCoddyKit上の無料C++ Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはC++ Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 C++ Academyコースには全4レッスンが含まれています。

コルーチンとしてのジェネレーター

ジェネレーターは、値を一度に1つずつ返すコルーチンです。ジェネレーターを呼び出すたびに次の値が生成され、処理が中断されます。

ジェネレーター型

入れ子になったpromise_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 {}; }
        void return_void() {}
        std::suspend_always yield_value(T value) {
            current_value = value;
            return {};
        }
        void unhandled_exception() { std::terminate(); }
    };

    std::coroutine_handle<promise_type> h;
    // ... constructors, destructor, next() ...
};

ジェネレーターの使用

一度定義すれば、ジェネレーターはPythonのyieldのように扱えます。

Generator<int> counting() {
    int n = 0;
    while (true) co_yield n++;
}

auto g = counting();
for (int i = 0; i < 5; ++i) {
    std::cout << g.next() << " ";
}
// 0 1 2 3 4

coroutine_handle

コンパイラーはstd::coroutine_handleを返します。これは中断されたコルーチンを表し、resume()やdestroy()を呼び出したり、done()を確認したりできます。

中断ポイント

各co_yieldで処理が中断されます。呼び出し側がresume()を呼び出すと、次の中断ポイントまたはコルーチンの終了まで処理が続行されます。

initial_suspendとfinal_suspend

2つのカスタマイズポイントがあります。

  • initial_suspend — 遅延開始にはsuspend_alwaysを、即時開始にはsuspend_neverを返します
  • final_suspend — クリーンアップを制御します。適切に破棄するため、通常はsuspend_alwaysを使用します

C++23のstd::generator

C++23では<generator>にstd::generatorが追加されました。一般的な用途であれば、型を自分で実装する必要はなくなりました。

#include <generator>

std::generator<int> counting() {
    int n = 0;
    while (true) co_yield n++;
}

範囲ベースのfor

ジェネレーター型がbegin/endをサポートしていれば、範囲ベースのforがそのまま使えます。

for (int x : counting()) {
    if (x >= 10) break;
    std::cout << x;
}

PullとPushのセマンティクス

ジェネレーターはpullベースです。呼び出し側が反復処理を進めます。Pushベースのコルーチンは非同期タスクです。

使用例

ジェネレーターは次の用途に適しています。

  • 遅延シーケンス(フィボナッチ数列、素数、1行ずつ読み取るファイルリーダー)
  • データをすべてメモリに展開しないストリーミング処理
  • 木構造の反復処理

メモリに関する考慮事項

コルーチンフレームは、デフォルトではヒープに割り当てられます。インライン化が可能な場合、コンパイラーが割り当てを省略することもあります。性能が重要な場合は計測してください。

調べてみたいライブラリ

学習には、Lewis Bakerによるcppcoroがおすすめです。ドキュメントが充実したジェネレーター型とタスク型を提供しています。Boost.Asioはコルーチンに対応したI/Oを提供します。C++23以降では標準ライブラリのサポートも追加されています。

確認問題

ジェネレーターコルーチンで使用するC++23標準ライブラリの型は何ですか?

まとめ

ジェネレーターコルーチンは、co_yieldを使って値を遅延的に生成します。promise_typeを含むクラスとして実装します。C++23ではstd::generatorが標準化されました。ジェネレーターは遅延シーケンスやストリーミングに適しています。

よくある質問

「シンプルなジェネレーターの実装」レッスンは無料ですか?

はい。「シンプルなジェネレーターの実装」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C++ Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C++ Academyコースには全4レッスンが含まれています。

「シンプルなジェネレーターの実装」で何を学びますか?

値を遅延的に生成するジェネレーターコルーチンを構築します。 ブラウザで直接実行するハンズオンコードでC++ Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

C++ Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのC++ Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。

「シンプルなジェネレーターの実装」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このC++ Academyレッスンでコードを書いて実行できますか?

はい。すべてのC++ Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. コルーチンの概念:co_await、co_yield、co_return
  2. シンプルなジェネレーターの実装
  3. 非同期タスクとawaiter型
  4. コルーチンフレームの割り当て
← C++ Academyに戻る