乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      實(shí)現(xiàn)functor - 增強(qiáng)型的函數(shù)指針

       just_person 2012-02-10

      實(shí)現(xiàn)functor - 增強(qiáng)型的函數(shù)指針

      作者:Kevin Lynx

      需求:

      開發(fā)一種組件,用以包裝C函數(shù)、通常的函數(shù)對(duì)象、成員函數(shù),使其對(duì)外保持一種一致的接口。我將最終的
      組件稱為functor,這里的functor與loki中的functor以及boost中的function功能一致,同STL中的functor
      在概念層次上可以說也是一樣的。那么,functor其實(shí)也可以進(jìn)一步傳進(jìn)其他functor構(gòu)成新的functor。

      C++世界里還有一種組件,稱做bind(er),例如STL中的binder1st、binder2nd,以及boost中的bind。所謂
      的bind是將一些參數(shù)與函數(shù)之類的關(guān)聯(lián)起來,當(dāng)執(zhí)行該bind創(chuàng)建的對(duì)象時(shí),庫會(huì)自動(dòng)將之前bind的參數(shù)傳
      遞給bind創(chuàng)建的對(duì)象。bind創(chuàng)建出來的對(duì)象在某種程度上來說也是一種functor。

      實(shí)現(xiàn):

      包裝C函數(shù)和函數(shù)對(duì)象的functor事實(shí)上是一致的,而實(shí)現(xiàn)包裝成員函數(shù)的functor則需要多傳入一個(gè)對(duì)象參數(shù)。
      因此這里先討論包裝C函數(shù)和函數(shù)對(duì)象的functor。

      包裝C函數(shù):

      思考下各種不同的C函數(shù)的共同點(diǎn)和不同點(diǎn),共同點(diǎn)就是這些函數(shù)都有一個(gè)返回值,參數(shù)個(gè)數(shù)可能相同,可能
      不同,參數(shù)類型可能相同可能不同??紤]到模板對(duì)于類型的泛化特性,對(duì)于參數(shù)類型來說,可以輕松實(shí)現(xiàn)無
      關(guān)性。而至于參數(shù)個(gè)數(shù)的泛化,則要復(fù)雜點(diǎn)。這里先考慮實(shí)現(xiàn)參數(shù)個(gè)數(shù)為1個(gè)的functor:

      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;
      }
      ;


      要使用這個(gè)類模板,可以這樣:

      functor<intint> cmd( func ); // int func( int )
      cmd( 1 );


      這樣,functor這個(gè)類模板就可以保存所以只有一個(gè)參數(shù)返回值任意的函數(shù)。但是這里首要的問題是,這個(gè)
      類模板無法保存具有相同類型的函數(shù)對(duì)象,例如函數(shù)對(duì)象:

      struct Func
      {
          int operator() ( int i )
          {
              return i;
          }

      }
      ;


      Func obj; 因?yàn)閛bj的類型事實(shí)上是Func,并不是一般的函數(shù)類型(例如 int (*)(int) )。那么,這里就需要
      將functor::func_type這個(gè)typedef泛化。

      包裝函數(shù)對(duì)象

      要實(shí)現(xiàn)這個(gè)目的,其實(shí)并不那么容易。一種比較直接的方法是我們把functor::func_type通過模板參數(shù)顯示地讓用戶配置,
      例如:

      template <typename _R, typename _P1, typename _FuncType>
      class functor
      {
      public:
       typedef _FuncType func_type;
       //以下內(nèi)容相同


      那么,現(xiàn)在就可以這樣使用functor:

      functor<intintint(*)(int)> cmd( func );
      cmd( 1 );
      // 測(cè)試函數(shù)對(duì)象
      Func obj;
      functor<intint, Func> cmd2( obj );
      cmd2( 2 );


      自動(dòng)推導(dǎo)類型:

      但是,這種顯示指定functor保存的函數(shù)(函數(shù)對(duì)象)的類型顯然是不方便的。我希望functor可以自動(dòng)獲取我們要
      保存的東西(C函數(shù),函數(shù)對(duì)象,為方便起見,以下全部簡(jiǎn)稱為函數(shù))的類型。而一個(gè)函數(shù)模板正可以做到這一點(diǎn)。
      以下簡(jiǎn)寫很多思考過程,直接給出一個(gè)解決方案:

      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;
      }
      ;


      代碼多了一倍,還增加了多態(tài)機(jī)制,使用了動(dòng)態(tài)內(nèi)存分配(這總會(huì)為我們?cè)黾勇闊赃@些,就是為了提供
      給用戶一個(gè)方便一致的接口?,F(xiàn)在我們可以這樣使用functor:

      functor<intint> cmd1( func );
      cmd1( 1 );

      Func obj;
      functor<intint> cmd2( obj );
      cmd2( 2 );


      雖然目標(biāo)實(shí)現(xiàn)了,可是看上去并不完美。礙眼的就是那個(gè)virtual,以及new/delete。不過因?yàn)檫@里離我的最終
      目標(biāo)還很遠(yuǎn),所以姑且不管這些。接下來要實(shí)現(xiàn)的是讓functor支持任意個(gè)參數(shù)(事實(shí)上任意個(gè)是不可能的)。

      讓更多的類型加入進(jìn)來:

      這里支持任意個(gè)參數(shù)似乎不現(xiàn)實(shí),因?yàn)镃++并不支持這樣的語法形式:

      template <typename _R, >
      class functor;


      也就是說模板并不支持可變參數(shù)。(可變參數(shù)那是C里面的東西,C++本身就不鼓勵(lì))

      這里,最簡(jiǎn)單的實(shí)現(xiàn)方法就是定義各種functor,支持0個(gè)參數(shù)的functor,支持一個(gè)參數(shù)的functor(我們以上實(shí)現(xiàn)的),
      支持兩個(gè)參數(shù)的functor,等等。相應(yīng)的,我們給每一個(gè)functor命名為functor0,functor1,functor2,。。。

      這確實(shí)是一種樸實(shí)的解決方法,但同時(shí)看上去也確實(shí)很不優(yōu)雅。我們其實(shí)完全可以通過一種模板技術(shù)讓functor1這種
      丑陋的命名方式消失,這就是模板偏特化(partial specialization)。

      Loki中的魔法:

      首先我們要讓functor這個(gè)頂層類可以看上去似乎支持可變長(zhǎng)度的模板參數(shù)。這個(gè)可以通過loki的TypeList實(shí)現(xiàn)。但是
      我們這里并不會(huì)用到特別復(fù)雜的TypeList技術(shù)。所謂TypeList,大致上核心在于以下類型:

      template <typename _T, typename _U>
      struct type_list
      {
       typedef _T head_type;
       typedef _U tail_type;
      }
      ;


      然后我們可以以一種遞歸的方式去容納任意長(zhǎng)度的類型列表(所謂type list):
      type_list<int, type_list<char, float> >
      在實(shí)際實(shí)現(xiàn)時(shí),我們通常會(huì)為每一個(gè)type list添加一個(gè)在loki中叫null_type的類型,就像C字符串末尾的'\0'一樣:
      type_list<int, type_list<char, null_type> >
      而null_type很簡(jiǎn)單,就是一個(gè)沒有任何東西的空類型:

      struct null_type { };


      為了更方便地產(chǎn)生type_list,我們按照loki中的做法,定義一系列的宏:

      #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)容基本和<C++設(shè)計(jì)新思維>部分內(nèi)容相同

      講述了以上基本內(nèi)容(我希望你能理解),接下來我要闡述下我的目的。我會(huì)把新的functor定義成:

      template <typename _R, typename _ParamList>
      class functor;


      如你所見,這和之前的functor本質(zhì)上是一樣的,我只不過改變了一個(gè)模板參數(shù)的名字(_ParamList)。現(xiàn)在當(dāng)我們使用
      functor的時(shí)候,會(huì)這樣:

      functor<voidvoid>
      functor<int, TYPE_LIST1( char )>
      functor<void, TYPE_LIST2( charfloat )>


      我們回頭看下之前創(chuàng)建的functor模塊的三個(gè)類是如何相互關(guān)聯(lián)的:functor提供給外部用戶接口,handler保存函數(shù)、回調(diào)
      函數(shù),handler_base則主要是提供給functor一個(gè)可以保存的類型(所以functor里保存的是functor_base)以及聲明各種接口。
      為什么需要提供handler_base,而不直接保存handler?因?yàn)閔andler需要保存函數(shù)的類型_FuncType,而這個(gè)類型只能在functor構(gòu)造
      函數(shù)里被提取出來。局限于這個(gè)原因,我加入了handler_base,并不得不加入了virtual,而為了滿足virtual的需要,我進(jìn)一步
      不得不將handler方在堆棧上。

      現(xiàn)在,我要實(shí)現(xiàn)通過functor不同的模板參數(shù)(主要在于_ParamList),產(chǎn)生不同的handler_base。關(guān)鍵在于我要產(chǎn)生各種不同的
      handler_base!現(xiàn)在我省略很多思考過程,直接給出一種架構(gòu):

       

      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 );
       }

       ///省略部分代碼

       
      現(xiàn)在,各種偏特化版本的handler_base,其實(shí)就相當(dāng)于實(shí)現(xiàn)了各種參數(shù)個(gè)數(shù)的functor,也就是functor0,functor1等。但是
      現(xiàn)在有個(gè)很直接的問題,例如當(dāng)functor<void, int>定義了一個(gè)參數(shù)時(shí),functor::handler_type里就沒有param2_type之類的
      類型定義,使用的偏特化版本handler_base也沒有部分param之類的類型定義。這會(huì)引起編譯出錯(cuò)。為了解決這個(gè)辦法,我不得
      不再引入一個(gè)用于類型定義的基類:

      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:添加更多類型定義
      }
      ;


      然后各種偏特化handler_base版本從handler_type_base繼承:

      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;
      }
      ;


      解決了這個(gè)編譯錯(cuò)誤問題,整個(gè)functor就基本實(shí)現(xiàn)了?,F(xiàn)在可以這樣使用functor:
      沒有參數(shù)的函數(shù): 

      functor<voidvoid> cmd4( func3 );
      cmd4();


      兩個(gè)參數(shù)的函數(shù):

      functor<void, TYPE_LIST2( intchar)> cmd3( func2 );
      cmd3( 3, 'a' );


      我稍微提下編譯器大致的處理方法:當(dāng)functor<void, void> cmd4( func3 )時(shí),functor::handler_type為handler_base<void, void>偏特
      化版本。該版本定義了void operator()()函數(shù)。當(dāng)cmd4()時(shí),就會(huì)調(diào)用到handler::operator()()函數(shù)。該函數(shù)回調(diào)func3函數(shù),完成調(diào)用。

      完結(jié),將成員函數(shù)包含進(jìn)來:

       關(guān)于包裝成員函數(shù),其實(shí)很簡(jiǎn)單,只是在調(diào)用時(shí)需要一個(gè)該類的對(duì)象而已。這里直接從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;
      }
      ;


      在functor中加入另一個(gè)構(gòu)造函數(shù):
       

      template <typename _ObjType, typename _FuncType>
      functor( _ObjType &obj, _FuncType func ) :
       _handler( new mem_handler<_R, _ParamList, _FuncType, _ObjType>( obj, func ) )
      {
      }


      一切都很完美。使用時(shí):

      Test obj2; // Test是一個(gè)類
      functor<void, TYPE_LIST1( int)> cmd5( obj2, &Test::display );
      cmd5( 1 );

       

      結(jié)束語:
      雖然我們最終的目的實(shí)現(xiàn)了,但是這還是不夠完美。我們還要處理functor的拷貝行為,因?yàn)閒unctor天生就是被用來
      四處拷貝的。一旦涉及到拷貝,我們就不得不小心翼翼地處理好functor中的那個(gè)被new出來的對(duì)象。作為一個(gè)C++程序員,
      你應(yīng)該時(shí)刻警惕放在heap上的東西,建立對(duì)heap上的警覺感是很重要的。這里我不得不承認(rèn)在后期實(shí)現(xiàn)中,我直接搬了
      loki中的很多方案。如果你不想讓這個(gè)functor看上去那么優(yōu)雅,那你完全可以寫出functor0,functor1之類的東西。

      參考資料:
      <C++ template>類模板的偏特化章節(jié)
      <Modern C++ design>type list, functor章節(jié)
      loki::functor源代碼
      boost:;function源代碼
      stl::bind1st源代碼
      stl::ptr_fun相關(guān)源代碼

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多