ゆとりーなの日記

日記的な事を書いて行くと思はれる

ラムダさんとバインドさん

コンテナにクラス型をぶち込んだ時、それらをアルゴリズムを使って捜査しようとすると以下の方法があります。

#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>

class Hoge {
public:
  // コンストラクタとか
  void hogeHoge() {std::cout << "ほげほげ" << std::endl;}
};

int main() {
  std::vector<Hoge> hoge;
  // とにかく要素を挿入
  std::for_each(hoge.begin(), hoge.end(), std::bind(&Hoge::hogeHoge, std::placeholders::_1));
}

もう面倒臭いのでtr1は付けません。VC++2010だと要らないみたいですし(付けても大丈夫)。
同じことをラムダ式を使ってやることもできることに気付きました。

int main() {
  std::vector<Hoge> hoge;
  // とにかく要素を挿入
  std::for_each(hoge.begin(), hoge.end(), [](const Hoge &x) {x.hogeHoge();});
}

VC++2008SP1を使っていた時代は、Boostなしではラムダ式を使えなかったので、上のbind一択で使っていたのですが、VC++2010になってラムダ式が使えるようになったのでどっちにしようかなと悩むようになったわけです。多分どちらもそれっぽい関数オブジェクトを勝手に生成してるんだと私は勝手に解釈しているので速度にそんなに差はないと思います。というわけで論点は読みやすさと書きやすさになります。
長さは若干ラムダ式の方が短いです。std::bindの方は、Boost時代には何の修飾もつかなかった_1がstd::placeholders::_1になってしまった事がでかいです。個人的にはusing namespaceを使うことには反対なのでこの長さはどうしようもありません。というわけで、私的には書きやすさではラムダ式に歩がある様に思えます。
続いて読みやすさの方。std::bindはかなり特殊な構文になっていると個人的には思います。メンバ関数ポインタっぽいものに、std::placeholders::_1といった見慣れないものも出てきます。std::placeholders::_1が何を表しているのか私は暫く分かっていませんでした。最近になって、コンテナの要素っぽいものが入る様にする記号なんだな〜と思うようになってきましたが、ぱっと見難しいです。一方ラムダ式の方も[]の怪しい使い方など、見慣れないものもありますが、std::placeholders::_1の部分を引数っぽく書くことが出来るし、中身に見慣れたメンバ関数呼び出しを書くことになるのでやや読みやすいのかなと思います。なんというか目に優しいというか。