std::experimental::generator
もう一つ、<experimental/generator>にgeneratorという名のフシギなクラス・テンプレートが用意されています。これは近未来のC++に提案されているresumable functionsを実現するためのクラスです。
コレを使うと「末尾の見えない集合」を簡単に扱うことができるようになります。というのも、C++にあらたなキーワード:yield が追加されるんです、ちょっとやってみましょう。
初項a、公比rの等比数列を生成する関数:geometric_progression(a,r) を定義します。
初項a、公比rの等比数列ですから、生成される数列はa, a*r, a*r*r, a*r*r*r ……ですが、この列に"末尾"はありません。つまりvector<double>などのコンテナを返すことができません。こんなシチュエーションでgeneratorとyieldの出番となります。
#include <iostream> #include <experimental/generator> /* * 等比数列: a * r^n (n = 0, 1, 2...) */ template<typename T> std::experimental::generator<T> geometric_progression(T a, T r) { // 無限ループで a, a*r, a*r*r, ... を yieldする while ( true ) { yield a; a *= r; } } int main() { using namespace std; // '一割増'を、元の2倍を超えるまで行う auto container = geometric_progression(1.0, 1.1); for ( auto iter = begin(container); iter != end(container); ++iter ) { cout << *iter << endl; if ( *iter > 2.0 ) break; } }
std::experimental::generator<T>は標準コンテナと同様に扱えるので、range-based forにも対応します:
// '一割増'を、元の2倍を超えるまで行う for ( auto item : geometric_progression(1.0, 1.1) ) { cout << item << endl; if ( item > 2.0 ) break; }
yieldは近未来のキーワードで、コンパイル時に/awaitオプションつけないとコンパイラに怒られるのでご注意を。