functor


	ところで、STLで思い出しましたが、みなさんは関数オブジェクト(function object = functor)というのを知っていますか?
	
	LISPは、関数自体がfirst class objectなので、関数閉包(function enclosure)と言って、関数自体の持ち歩きが出来て関数の合成とかが非常に簡単に出来たのですが、あれを擬似的にC++で行なうにはどうすればいいのでしょうか?関数ポインタを渡してコールバックは出来ても、それでは関数の合成は出来ないからです。
	
	C++の世界でfunctor(=関数オブジェクト)と言うと、operator( ) を定義したクラスのことを言います。たとえば、find_ifのテンプレートを見ましょう。_Prは、functorです。
	
	        // TEMPLATE FUNCTION find_if
	template<class _II, class _Pr> inline
	    _II find_if(_II _F, _II _L, _Pr _P)
	    {for (; _F != _L; ++_F)
	        if (_P(*_F))
	            break;
	    return (_F); }
	
	
	_P(*_F)とあるのは、_Prはfunctorで、_Prにはoperator ( )が定義されているので、このオーバーロードされた関数が呼び出されます。見ての通り、_Prのとる引数は一つ(unary_function/単項関数)であることが、前提となります。引数を可変にするテンプレート展開が出来ないので仕方ないという意味もありますが、このへんはC++のテンプレート展開の甘さだと私は思います。
	
	functorの合成について見てみましょう。
	
	        // TEMPLATE STRUCT greater
	template<class _Ty>
	    struct greater : binary_function<_Ty, _Ty, bool> {
	    bool operator()(const _Ty& _X, const _Ty& _Y) const
	        {return (_X > _Y); }
	    };
	
	
	boolを返す二項関数(binary_function)としてgreaterは実装されてます。(structでもclassと同様に継承も出来れば関数も書けるというのは、意外と知らない人が多いかも知れません) こいつと、bind2ndで、関数合成をやってみましょう。
	
	        // TEMPLATE FUNCTION bind2nd
	template<class _Bfn, class _Ty> inline
	    binder2nd<_Bfn> bind2nd(const _Bfn& _X, const _Ty& _Y)
	        {return (binder2nd<_Bfn>(_X,
	            _Bfn::second_argument_type(_Y))); }
	
	
	bind2ndは、binder2ndというfunctorを返す関数テンプレートです。2項関数の第2引数に、値を突っ込んで、単項関数化するわけです。
	
	    remove_if(lst.begin( ),lst.end( ),bind2nd(greater<int>( ) , 5);
	
	STLのremove_ifと組み合わせて、上例のように書けば、5より大きな要素をもつものを全て削除できます。greater<int>のあとに( )があるのは、C++に馴染みの少ない人には見慣れない構文でしょうが、これ
	
	    CObject( ).func( ); // CObjectのテンポラリオブジェクトを作り、そのメンバ関数funcを呼び出す。
	
	と同様、functorのテンポラリオブジェクトを作るためにコンストラクタを呼び出しているのです。ここで面白いのは、このように行なったfunctorの合成は、インライン展開される(たぶんね^^;)ということです。おかげで、効率が非常に良いです。
	
	問題として挙げられる点は、テンプレート展開に頼るので、静的な(コンパイル時の)functor合成しかできないこと、そして、関数が単項関数か二項関数か、それ以外かを最終的に処理する関数(上例ではremove_if)が決め付けてしまうことが難点です。そもそも、remove_ifがfunctorに規定すべきことはboolを返す関数であるということだけで、functorの引数に関しては口出ししてくるのはおかしいです。上例では、greate<int>というfunctorは二項関数であり、それをbind2ndで単項関数化しています。この仕組みがダサイこと極まりないのです。テンプレートで文字列をソースコード中に展開する機能、たとえば
	
	    remove_if(lst.begin( ),lst.end( ),element:"element > 5");
	
	というようなことが出来れば、bind2ndやgreaterのような似非functorの合成作業なんて不要になります。どうせ静的にしかfunctorの合成が出来ないのならば、これぐらいでも十分です。
	
	私がSTLのalgorithmがクソだと思うのは、このへんの事情からで、functorはともかく、algorithmはほとんど使いものにならないです。しかも、functorもよほど限定されたシーンでないと使いものになりません。私に言わせれば、テンプレートの展開が甘いがために無理矢理、別の機構で代替しているだけで、本来の数学的なfunctorの意味合いからはほど遠いです。