C++教科書/標準ライブラリ編/<generator> の章
編集はじめに
編集C++23では、非同期コードを同期的な構文で記述できる新しい言語機能であるコルーチンが導入されました。ジェネレータは、コルーチンの中でも、一連の値を生成できる特別な種類のコルーチンです。
この章では、C++23における<generator>
ヘッダーで提供されるジェネレータの機能について解説します。
概念
編集まず、ジェネレータを理解する前に、view
という概念について説明します。view
は、範囲ライブラリで使用される軽量なデータソース表現です。範囲ライブラリは、汎用的なシーケンスを操作するためのライブラリですが、この章では詳細を省略します。
ジェネレータは、view
を継承したクラステンプレートであり、同期コルーチンジェネレータを表します。つまり、ジェネレータは、非同期処理を同期的な構文で記述できるコルーチンの一種です。
std::generatorクラステンプレート
編集std::generator
は、ジェネレータを表すクラステンプレートです。以下のテンプレートパラメータを持ちます。
Ref
: ジェネレータが生成するデータの参照型V
(省略可能): ジェネレータが生成する値の型 (デフォルトはvoid
)Allocator
(省略可能): ジェネレータが使用するメモリの管理に用いるアロケータ (デフォルトはvoid
)
std::pmr::generator
は、多態性メモリアロケータを使用するための便利なエイリアスです。
std::generator
には、以下のメンバ関数が用意されています。
- コンストラクタ:
- コピーコンストラクタ (
generator(const generator&)
) は禁止されていますが、移動コンストラクタ (generator(generator&& other)
) は効率的なリソース管理のために許可されています。
- コピーコンストラクタ (
- デストラクタ: (
~generator()
) は、適切なクリーンアップを行います。 - 移動代入演算子: (
generator& operator=(generator other)
) は、効率的なリソース転送を行います。 - イテレータ:
begin()
: 生成されたシーケンスの先頭のイテレータを返します。end()
: シーケンスの終端を示す番兵値を返します (常にdefault_sentinel_t
です)。
std::generator::promise_typeネストクラス
編集std::generator::promise_type
は、std::generator
のネストクラスであり、コルーチンの実行と呼び出し側との通信を管理します。以下のメンバ関数が用意されています。
get_return_object()
: コルーチンを表すジェネレータオブジェクトを返します。initial_suspend()
: 最初はサスペンドしないことを示します。final_suspend()
: 終了時のサスペンド処理を処理します (詳細は省略可)。yield_value()
: さまざまな型の値 (参照、rvalue参照、または別のジェネレータ) を生成するための関数。return_void()
: ジェネレータが値を生成しない場合に内部で使用されます。unhandled_exception()
: ジェネレータコルーチン内でスローされた例外を処理します。- メモリの割り当てと解放のための関数 (
operator new
とoperator delete
) は、内部メモリ管理に使用されます。
std::generator::iteratorネストクラス
編集std::generator::iterator
は、ジェネレータが生成する値のシーケンスを反復するための軽量なイテレータ型です。以下のメンバ関数が用意されています。
operator*
: 現在のイテレータが指す値を返します。operator++
: イテレータをインクリメントします。operator==
: イテレータがシーケンスの終端に達しているかどうかを比較します。
例
編集以下は、ジェネレータを使用して1から10までの整数を生成する例です。
#include <generator> #include <iostream> std::generator<int> generate_integers(int start, int end) { for (int i = start; i <= end; i++) { co_yield i; } } int main() { for (int i : generate_integers(1, 10)) { std::cout << i << " "; } std::cout << std::endl; }
ジェネレータの利用例
編集ジェネレータは、さまざまな用途に使用できます。以下に、いくつかの例を示します。
- 遅延評価: ジェネレータを使用して、必要なときにのみ値を計算する遅延評価アルゴリズムを実装できます。これは、メモリ使用量とパフォーマンスを向上させるのに役立ちます。
- 非同期処理: ジェネレータを使用して、非同期処理を同期的な構文で記述できます。これは、ネットワーク I/O やファイル入出力などのタスクに役立ちます。
- データストリーム: ジェネレータを使用して、外部データソースからデータストリームを生成できます。これは、ファイルやネットワーク接続からのデータの処理に役立ちます。
まとめ
編集C++23における<generator>
ヘッダーは、コルーチンとジェネレータを使用して、非同期コードを同期的な構文で記述するための強力なツールを提供します。ジェネレータは、さまざまな用途に使用でき、コードの可読性と保守性を向上させるのに役立ちます。
補足
編集- この章では、ジェネレータの基本的な概念と機能について説明しました。より詳細な情報は、C++23 標準規格またはその他の資料を参照してください。
- ジェネレータは、C++23 の新機能であり、すべてのコンパイラでサポートされているわけではありません。使用前に、コンパイラのドキュメントを確認してください。