この前、少し初期化が面倒な数値のリストを作らなければならなくなった。しかも結構急いでいた。
適当な例として以下のようなものを考える。
const std::vector<std::size_t> indices{1,4,7,10,13, ... 298}; //流石に手では書けない
こんなもの、for
文を使えばいいのでは?
std::vector<std::size_t> indices; for(std::size_t i=0; i<100; ++i) indices.push_back(i*3+1);
上のコードは完璧ではない(ex. reserve
するべきだ)が、とりあえず動きはする。
しかしその後少し面倒なことをするので、できれば私はこれをconst
にしたかった。不注意で書き換えてしまうのが怖かった。
外部でCSVを作って、
const std::vector<std::size_t> indices{ #include "indices.csv" };
とするのも一瞬考えたが、流石に却下した。
例えばBoost Iteratorを使えば、これは普通にIterator
を2つ渡してその範囲を使って初期化するコンストラクタが使える。
const auto f = [](std::size_t i){return i*3+1;}; const std::vector<std::size_t> indices( boost::make_transform_iterator( boost::make_counting_iterator<std::size_t>(1), f), boost::make_transform_iterator( boost::make_counting_iterator<std::size_t>(100), f) );
だが長い。正しいやり方だが、その時私は本当に急いでいたので(実際、マクロ定義をして一部のコードを生成した程だ)、これはちょっと許容できなかった。
そして、関数の返却値としてならconst
で受けられる、と思ったあと、一瞬関数を作ろうとして、すぐに一時的なその場で使える関数の存在を思い出した。
lambda
だ。
const std::vector<std::size_t> indices = [](){ // ラムダ定義開始 std::vector<std::size_t> v; for(std::size_t i=0; i<100; ++i) v.push_back(i*3+1); return v; }(); // lambda定義を終了し "}"、即座に呼び出す "()"。 // その場でラムダの中身が実行され、値が返る。それが`indices`になる。
その場でlambda
を作って、その中で必要なものを生成し、その場でconst
なものに代入した。
今までstd::algorithm
との組み合わせとか、関数を渡すというような状況でばかり使ってきたが、lambda
にはこんな使い方もある。綺麗な書き方かどうかはおいておいて。