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扱いであればあらゆる使用に関して文句は言いません。 なにかあれば下記メールアドレスへ。