实现functor - 增强型的函数指针作者:Kevin Lynx 需求: 开发一种组件,用以包装C函数、通常的函数对象、成员函数,使其对外保持一种一致的接口。我将最终的 C++世界里还有一种组件,称做bind(er),例如STL中的binder1st、binder2nd,以及boost中的bind。所谓 实现: 包装C函数和函数对象的functor事实上是一致的,而实现包装成员函数的functor则需要多传入一个对象参数。 包装C函数: 思考下各种不同的C函数的共同点和不同点,共同点就是这些函数都有一个返回值,参数个数可能相同,可能 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; } };
包装函数对象: 要实现这个目的,其实并不那么容易。一种比较直接的方法是我们把functor::func_type通过模板参数显示地让用户配置, template <typename _R, typename _P1, typename _FuncType> class functor { public: typedef _FuncType func_type; //以下内容相同
functor<int, int, int(*)(int)> cmd( func ); cmd( 1 ); // 测试函数对象 Func obj; functor<int, int, Func> cmd2( obj ); cmd2( 2 );
但是,这种显示指定functor保存的函数(函数对象)的类型显然是不方便的。我希望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 );
让更多的类型加入进来: 这里支持任意个参数似乎不现实,因为C++并不支持这样的语法形式: template <typename _R, > class functor;
这里,最简单的实现方法就是定义各种functor,支持0个参数的functor,支持一个参数的functor(我们以上实现的), 这确实是一种朴实的解决方法,但同时看上去也确实很不优雅。我们其实完全可以通过一种模板技术让functor1这种 Loki中的魔法: 首先我们要让functor这个顶层类可以看上去似乎支持可变长度的模板参数。这个可以通过loki的TypeList实现。但是 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
讲述了以上基本内容(我希望你能理解),接下来我要阐述下我的目的。我会把新的functor定义成: template <typename _R, typename _ParamList> class functor;
functor<void, void> functor<int, TYPE_LIST1( char )> functor<void, TYPE_LIST2( char, float )>
现在,我要实现通过functor不同的模板参数(主要在于_ParamList),产生不同的handler_base。关键在于我要产生各种不同的
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' );
完结,将成员函数包含进来: 关于包装成员函数,其实很简单,只是在调用时需要一个该类的对象而已。这里直接从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 );
结束语: 参考资料: |
|
来自: just_person > 《C 》