この前、少し初期化が面倒な数値のリストを作らなければならなくなった。しかも結構急いでいた。
適当な例として以下のようなものを考える。
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
を作って、その中で必要なものを生成し、その場でconst
なものに代入した。
今までstd::algorithm
との組み合わせとか、関数を渡すというような状況でばかり使ってきたが、lambda
にはこんな使い方もある。綺麗な書き方かどうかはおいておいて。