STLの functional には、mem_fun*, bind* という、 まあ STL内では割と難しめの関数アダプタが入っています。 それをここで説明する気はありません。 知らなければ Effective STL あたりを購入して下さい。
STLのこれらにはちょっと嫌な仕様が二つあります。 refer to refer 問題というのと、 ptr_fun っていうのが邪魔、って問題です。 まあ、実際にコードを見て頂くのが早いでしょう。
functionalTest.cc (実行はできません)
まず、refer to refer から。
class Class { public: void func1(int i) {} void func2(Class& c) {} };
こういうクラスがあって、
std::vector<Class*> cs; Class c; // これは大丈夫です。 std::for_each(cs.begin(), cs.end(), std::bind2nd(std::mem_fun(&Class::func1), 1)); // refer to refer! #ifdef WATCH_ERROR std::for_each(cs.begin(), cs.end(), std::bind2nd(std::mem_fun(&Class::func2), c)); #endif // これは当然大丈夫です。 std::for_each(cs.begin(), cs.end(), boost::bind2nd(boost::mem_fun(&Class::func1), 1)); // refer to refer 関係無し。 std::for_each(cs.begin(), cs.end(), boost::bind2nd(boost::mem_fun(&Class::func2), c));
こうなっていて、ifdef で囲まれている所が STL の問題点です。 これは、func2 の引数が Class& で、 bind2nd でその型にもう一度 & を付けてしまっているため、 Class&& となってしまい、 これは標準 C++ では許されない型なので、 エラーになってしまいます。
これを防ぐため、boost ではテンプレート特別バージョンを使って、 Class& なら、Class&、Class なら Class& を返す、 不思議なメタ関数を用意しています。 それが、boost::call_traits というもので、 それを使って書き直されたものが用意されているのです。
まあ、慣れない内は std:: でエラーが出たら、 boost:: に変えればいいでしょう。 型の調整はコンパイル時に行われるので、 実行時間に影響は出ないので、 いっそデフォルトで boost:: でも良いかと思います。
次、ptr_fun の追い出し。
void func(int i, int j) {}
という関数があって、
std::vector<int> is; #ifdef WATCH_ERROR // これは、ダメで、 std::for_each(is.begin(), is.end(), std::bind2nd(&func, 1)); #else // こうしなければならない。 std::for_each(is.begin(), is.end(), std::bind2nd(std::ptr_fun(&func), 1)); #endif std::for_each(is.begin(), is.end(), boost::bind2nd(&func, 1));
まあ、見ればわかりますね。 これも似たような原理で、 function object traits というもので 関数が渡されたか、関数オブジェクトが渡されたかを コンパイルタイムに判断しています。 解る人は以下を見れば意味が解るかと。 boost functional.hpp より。
template <class Operation> struct unary_traits_imp; template <class Operation> struct unary_traits_imp<Operation*> { typedef Operation function_type; typedef const function_type & param_type; typedef typename Operation::result_type result_type; typedef typename Operation::argument_type argument_type; }; template <class R, class A> struct unary_traits_imp<R(*)(A)> { typedef R (*function_type)(A); typedef R (*param_type)(A); typedef R result_type; typedef A argument_type; };
かっこいいなあ。
全てリンクフリーです。 コード片は自由に使用していただいて構いません。 その他のものはGPL扱いであればあらゆる使用に関して文句は言いません。 なにかあれば下記メールアドレスへ。