boost lambda

C++のライブラリ集boost.スレッド周りで使ってみようかと思っていたのだが,マニュアルを見ていたらlambdaとかあるので,思わずいじってしまった.

lambdaとはまあ,いわゆる無名関数.C++ではSTLで関数オブジェクトを使うようになっているわけだが,関数オブジェクトは別途定義しなければならないのであまり見通しがよくない.で,代わりに関数オブジェクトをその場で書いてしまおう,というわけだ.

シンタックスがかなり特殊で,キーワードを使わずに

_1, _2

といったアンダースコア+数字という変数名を使う.たとえば二つの変数を取り,和を返すというような無名関数はpythonではこんな感じ.

 (lambda x, y: x + y) (1, 2)

lambdaで定義した関数に引数 1と2を与えて評価している.

これをboost lambdaで書くとこんな感じ.

(_1 + _2) (1, 2);

キーワードもなにもなしだ.すごくない ? (菊地桃子風)

STLと組み合わせる

boost lambda は,もともとSTLと組み合わせて使うことを目的として作られている.例えばvectorの中身を表示するにはこうする.

vector<int> v(10);
...
for_each(v.begin(), v.end(), cout << _1 << "\n" );

おお,なんかすばらしい.と思うかもしれないが,こういう風に透過的に書けるケースは非常に例外的で,この場合iostreamにlambdaが対応しているからに過ぎない.例えば,この例で "\n" を std::endl に書き換えるだけでコンパイルが通らない.なんで?

iostream の代わりにprintfを使おうとしてもうまく行かない.

for_each(v.begin(), v.end(), printf("%d\n", _1) );

この書き方には間違いが2つある.

  1. 関数を書くときには直接書かずにbindを使う
  2. printf は可変引数関数なのでbindもうまく行かない.

printfを使うには,まずprintfを適当な固定引数の関数でラップしておいて,それをbindで用いる.

void printint(int i) {
	printf("%d\n", i);
}
for_each(v.begin(), v.end(), bind(printint, _1) );

まあ,この場合だと直接printintだけわたしても結果は同じなので意味ないですが.

for_each(v.begin(), v.end(), printint );

その他の構造

なんか if とか switchなどの制御構造も微妙なシンタックスでかけるらしい.しかしあまり複雑な構造を書くとどうせわかわからなくなっちゃうので,簡単に書ける場合だけにしておいた方が良さそうな気がする.

実装

実装は,ヘッダファイルだけ.つまりコンパイル時に関数オブジェクトに展開しているわけだ.オソルベシC++.ちなみにboost/lambda以下のhppは全部で19350行.なんというか...