實現(xiàn)functor - 增強(qiáng)型的函數(shù)指針作者:Kevin Lynx 需求: 開發(fā)一種組件,用以包裝C函數(shù)、通常的函數(shù)對象、成員函數(shù),使其對外保持一種一致的接口。我將最終的 C++世界里還有一種組件,稱做bind(er),例如STL中的binder1st、binder2nd,以及boost中的bind。所謂 實現(xiàn): 包裝C函數(shù)和函數(shù)對象的functor事實上是一致的,而實現(xiàn)包裝成員函數(shù)的functor則需要多傳入一個對象參數(shù)。 包裝C函數(shù): 思考下各種不同的C函數(shù)的共同點和不同點,共同點就是這些函數(shù)都有一個返回值,參數(shù)個數(shù)可能相同,可能 template <typename _R, typename _P1> class functor { public: typedef _R (*func_type)( _P1 ); public: explicit functor( const func_type &func ) : _func( func ) { } _R operator() ( _P1 p ) { return _func( p ); }![]() private: func_type _func; };![]() ![]()
functor<int, int> cmd( func ); // int func( int ) cmd( 1 );![]()
struct Func { int operator() ( int i ) { return i; } };![]()
包裝函數(shù)對象: 要實現(xiàn)這個目的,其實并不那么容易。一種比較直接的方法是我們把functor::func_type通過模板參數(shù)顯示地讓用戶配置, template <typename _R, typename _P1, typename _FuncType> class functor { public: typedef _FuncType func_type; // 以下內(nèi)容相同![]()
functor<int, int, int(*)(int)> cmd( func ); cmd( 1 ); // 測試函數(shù)對象 Func obj; functor<int, int, Func> cmd2( obj ); cmd2( 2 );![]()
但是,這種顯示指定functor保存的函數(shù)(函數(shù)對象)的類型顯然是不方便的。我希望functor可以自動獲取我們要 template <typename _R, typename _P1> struct handler_base { virtual _R operator() ( _P1 ) = 0; };![]() template <typename _R, typename _P1, typename _FuncType> class handler : public handler_base<_R, _P1> { public: typedef _FuncType func_type; public: handler( const func_type &func ) : _func( func ) { }![]() _R operator() ( _P1 p ) { return _func( p ); }![]() public: func_type _func; };![]() template <typename _R, typename _P1> class functor { public: typedef handler_base<_R, _P1> handler_type ; public: template <typename _FuncType> functor( _FuncType func ) : _handler( new handler<_R, _P1, _FuncType>( func ) ) { } ~functor() { delete _handler; }![]() _R operator() ( _P1 p ) { return (*_handler)( p ); }![]() private: handler_type *_handler; };![]() ![]()
functor<int, int> cmd1( func ); cmd1( 1 );![]() Func obj; functor<int, int> cmd2( obj ); cmd2( 2 );![]() ![]()
讓更多的類型加入進(jìn)來: 這里支持任意個參數(shù)似乎不現(xiàn)實,因為C++并不支持這樣的語法形式: template <typename _R, > class functor;![]()
這里,最簡單的實現(xiàn)方法就是定義各種functor,支持0個參數(shù)的functor,支持一個參數(shù)的functor(我們以上實現(xiàn)的), 這確實是一種樸實的解決方法,但同時看上去也確實很不優(yōu)雅。我們其實完全可以通過一種模板技術(shù)讓functor1這種 Loki中的魔法: 首先我們要讓functor這個頂層類可以看上去似乎支持可變長度的模板參數(shù)。這個可以通過loki的TypeList實現(xiàn)。但是 template <typename _T, typename _U> struct type_list { typedef _T head_type; typedef _U tail_type; };![]()
struct null_type { };![]()
#define TYPE_LIST1( T1 ) type_list<T1, null_type> #define TYPE_LIST2( T1, T2 ) type_list<T1, TYPE_LIST1( T2 )> #define TYPE_LIST3( T1, T2, T3 ) type_list<T1, TYPE_LIST2( T2, T3 )> /// etc![]() ![]()
講述了以上基本內(nèi)容(我希望你能理解),接下來我要闡述下我的目的。我會把新的functor定義成: template <typename _R, typename _ParamList> class functor;![]()
functor<void, void> functor<int, TYPE_LIST1( char )> functor<void, TYPE_LIST2( char, float )>![]()
現(xiàn)在,我要實現(xiàn)通過functor不同的模板參數(shù)(主要在于_ParamList),產(chǎn)生不同的handler_base。關(guān)鍵在于我要產(chǎn)生各種不同的
template <typename _R, typename _ParamList> struct handler_base;![]() template <typename _R> struct handler_base<_R, void> : public handler_type_base<_R> { virtual _R operator() ( void ) = 0; };![]() template <typename _R, typename _P1> struct handler_base<_R, TYPE_LIST1( _P1 )> : public handler_type_base<_R> { typedef _P1 param1_type;![]() virtual _R operator() ( _P1 ) = 0; };![]() /// TODO:添加更多類型的偏特化版本![]() template <typename _R, typename _ParamList, typename _FuncType> class handler : public handler_base<_R, _ParamList> { public: typedef _FuncType func_type;![]() typedef handler_base<_R, _ParamList> base_type; typedef typename base_type::param1_type param1_type; /// TODO:更多的類型定義 public: handler( const func_type &func ) : _func( func ) { }![]() _R operator() () { return _func(); }![]() _R operator() ( param1_type p ) { return _func( p ); } /// 省略部分代碼 /// functor template <typename _R, typename _ParamList> class functor { public: typedef handler_base<_R, _ParamList> handler_type ;![]() typedef typename handler_type::param1_type param1_type; typedef typename handler_type::param2_type param2_type; typedef typename handler_type::param3_type param3_type; /// TODO:更多類型 public: template <typename _FuncType> functor( _FuncType func ) : _handler( new handler<_R, _ParamList, _FuncType>( func ) ) { } ~functor() { delete _handler; }![]() _R operator() () { return (*_handler)(); }![]() _R operator() ( param1_type p ) { return (*_handler)( p ); } /// 省略部分代碼![]() ![]() template <typename _R> struct handler_type_base { typedef _R result_type; typedef null_type param1_type; typedef null_type param2_type; typedef null_type param3_type; /// TODO:添加更多類型定義 };![]()
template <typename _R, typename _P1, typename _P2> struct handler_base<_R, TYPE_LIST2(_P1, _P2 )> : public handler_type_base<_R> { typedef _P1 param1_type; typedef _P2 param2_type;![]() virtual _R operator() ( _P1, _P2 ) = 0; };![]() ![]()
functor<void, void> cmd4( func3 ); cmd4();![]()
functor<void, TYPE_LIST2( int, char)> cmd3( func2 ); cmd3( 3, 'a' );![]()
完結(jié),將成員函數(shù)包含進(jìn)來: 關(guān)于包裝成員函數(shù),其實很簡單,只是在調(diào)用時需要一個該類的對象而已。這里直接從handler_base派生: template <typename _R, typename _ParamList, typename _FuncType, typename _ObjType> class mem_handler : public handler_base<_R, _ParamList> { public: typedef _FuncType func_type; typedef _ObjType obj_type;![]() typedef handler_base<_R, _ParamList> base_type; typedef typename base_type::param1_type param1_type; typedef typename base_type::param2_type param2_type; typedef typename base_type::param3_type param3_type;![]() public: mem_handler( obj_type &obj, const func_type &func ) : _obj( obj ), _func( func ) { }![]() _R operator() () { return (_obj.*_func)(); }![]() _R operator() ( param1_type p ) { return (_obj.*_func)( p ); }![]() _R operator() ( param1_type p1, param2_type p2 ) { return (_obj.*_func)( p1, p2 ); }![]() private: obj_type &_obj; func_type _func; };![]() ![]()
template <typename _ObjType, typename _FuncType> functor( _ObjType &obj, _FuncType func ) : _handler( new mem_handler<_R, _ParamList, _FuncType, _ObjType>( obj, func ) ) { }![]()
Test obj2; // Test是一個類 functor<void, TYPE_LIST1( int)> cmd5( obj2, &Test::display ); cmd5( 1 );
結(jié)束語: 參考資料: |
|
|
來自: just_person > 《C 》