青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

woaidongmao

文章均收錄自他人博客,但不喜標題前加-[轉貼],因其丑陋,見諒!~
隨筆 - 1469, 文章 - 0, 評論 - 661, 引用 - 0
數據加載中……

實現functor - 增強型的函數指針

作者:Kevin Lynx

需求:

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

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

實現:

包裝C函數和函數對象的functor事實上是一致的,而實現包裝成員函數的functor則需要多傳入一個對象參數。
因此這里先討論包裝C函數和函數對象的functor。

包裝C函數:

思考下各種不同的C函數的共同點和不同點,共同點就是這些函數都有一個返回值,參數個數可能相同,可能
不同,參數類型可能相同可能不同。考慮到模板對于類型的泛化特性,對于參數類型來說,可以輕松實現無
關性。而至于參數個數的泛化,則要復雜點。這里先考慮實現參數個數為1個的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;
}
;


要使用這個類模板,可以這樣:

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


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

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

}
;


Func obj; 因為obj的類型事實上是Func,并不是一般的函數類型(例如 int (*)(int) )。那么,這里就需要
將functor::func_type這個typedef泛化。

包裝函數對象

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

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


那么,現在就可以這樣使用functor:

functor<int, int, int(*)(int)> cmd( func );
cmd(
1 );
// 測試函數對象
Func obj;
functor
<int, int, Func> cmd2( obj );
cmd2(
2 );


自動推導類型:

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

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:

functor<int, int> cmd1( func );
cmd1(
1 );

Func obj;
functor
<int, int> cmd2( obj );
cmd2(
2 );


雖然目標實現了,可是看上去并不完美。礙眼的就是那個virtual,以及new/delete。不過因為這里離我的最終
目標還很遠,所以姑且不管這些。接下來要實現的是讓functor支持任意個參數(事實上任意個是不可能的)。

讓更多的類型加入進來:

這里支持任意個參數似乎不現實,因為C++并不支持這樣的語法形式:

template <typename _R, >
class functor;


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

這里,最簡單的實現方法就是定義各種functor,支持0個參數的functor,支持一個參數的functor(我們以上實現的),
支持兩個參數的functor,等等。相應的,我們給每一個functor命名為functor0,functor1,functor2,。。。

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

Loki中的魔法:

首先我們要讓functor這個頂層類可以看上去似乎支持可變長度的模板參數。這個可以通過loki的TypeList實現。但是
我們這里并不會用到特別復雜的TypeList技術。所謂TypeList,大致上核心在于以下類型:

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


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

struct null_type { };


為了更方便地產生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


注:以上內容基本和<C++設計新思維>部分內容相同

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

template <typename _R, typename _ParamList>
class functor;


如你所見,這和之前的functor本質上是一樣的,我只不過改變了一個模板參數的名字(_ParamList)。現在當我們使用
functor的時候,會這樣:

functor<void, void>
functor
<int, TYPE_LIST1( char )>
functor
<void, TYPE_LIST2( char, float )>


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

現在,我要實現通過functor不同的模板參數(主要在于_ParamList),產生不同的handler_base。關鍵在于我要產生各種不同的
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 );
}

 
///省略部分代碼

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

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


解決了這個編譯錯誤問題,整個functor就基本實現了。現在可以這樣使用functor:
沒有參數的函數:

functor<void, void> cmd4( func3 );
cmd4();


兩個參數的函數:

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


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

完結,將成員函數包含進來:

關于包裝成員函數,其實很簡單,只是在調用時需要一個該類的對象而已。這里直接從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中加入另一個構造函數:
 

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

 

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

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

 

 

posted on 2008-03-17 11:13 Kevin Lynx 閱讀(1444) 評論(2)  編輯 收藏 引用 所屬分類: C++

評論

# re: 實現functor - 增強型的函數指針 2008-03-17 16:43 夢在天涯

functor 確實是比STL中的一大堆好用多了!統一!  回復  更多評論  

posted on 2008-08-31 21:41 肥仔 閱讀(358) 評論(0)  編輯 收藏 引用 所屬分類: C++ 模板

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲美女区一区| 久久国产天堂福利天堂| 欧美日韩精品二区| 欧美日韩免费高清一区色橹橹| 欧美 日韩 国产在线| 欧美激情一区二区三区 | 欧美成人一区二区三区在线观看| 久久视频在线免费观看| 久久亚洲精品一区二区| 欧美激情视频一区二区三区不卡| 亚洲剧情一区二区| 亚洲综合日韩| 乱人伦精品视频在线观看| 欧美激情一区二区三区在线视频观看| 欧美日韩免费一区二区三区视频| 国产精品久久久久久久午夜| 国产在线欧美| 亚洲免费av网站| 香蕉久久精品日日躁夜夜躁| 麻豆精品在线视频| 99视频超级精品| 久久婷婷国产综合精品青草| 欧美日韩无遮挡| 激情综合网激情| 亚洲伊人网站| 免费观看国产成人| 亚洲视频日本| 欧美精品网站| 在线高清一区| 欧美中日韩免费视频| 亚洲国产裸拍裸体视频在线观看乱了中文 | 欧美日韩一区在线| 一区二区三区自拍| 亚洲欧美精品| 亚洲精品国产系列| 久久亚洲精品伦理| 国产一区二区三区在线观看视频| 宅男精品视频| 亚洲国产精品一区二区尤物区| 亚洲私拍自拍| 国产一区二区三区久久久久久久久 | 亚洲伦理网站| 久久在线视频| 西瓜成人精品人成网站| 欧美日韩国产综合在线| 亚洲国产专区校园欧美| 久久综合成人精品亚洲另类欧美| 中文在线资源观看视频网站免费不卡| 蜜乳av另类精品一区二区| 国产综合欧美| 久久精品一本| 欧美一区二区三区四区高清| 国产精品主播| 性刺激综合网| 亚洲精品社区| 欧美日韩久久久久久| 亚洲毛片一区二区| 亚洲黄色av一区| 欧美搞黄网站| 日韩一级成人av| 亚洲精品日韩在线观看| 欧美人与禽猛交乱配| 一区二区三区不卡视频在线观看| 亚洲欧洲视频在线| 欧美日韩国产精品一区| 在线亚洲精品福利网址导航| 日韩视频在线免费| 欧美午夜电影一区| 亚洲先锋成人| 亚洲在线观看视频| 国产日韩在线亚洲字幕中文| 久久天堂av综合合色| 美女视频一区免费观看| 亚洲毛片视频| 亚洲一区二区欧美| 韩国av一区二区三区四区| 欧美成人一区二区| 欧美日韩成人在线观看| 亚洲一区免费在线观看| 午夜宅男久久久| 亚洲欧洲视频在线| 一区二区精品在线| 国产一区二区三区黄视频| 欧美.www| 国产精品成人免费精品自在线观看| 小黄鸭视频精品导航| 久久久久久久网| 亚洲午夜国产一区99re久久| 欧美在线啊v一区| 日韩一级片网址| 久久本道综合色狠狠五月| 99国产精品久久久久久久成人热| 亚洲伊人网站| 最近中文字幕日韩精品 | 一区二区三区偷拍| 亚洲欧美国产精品专区久久| 国内精品久久久久影院薰衣草| 免费欧美日韩国产三级电影| 欧美精品一区二区久久婷婷| 亚洲欧美日韩国产中文| 久久亚洲精品网站| 亚洲永久精品国产| 美女视频网站黄色亚洲| 性感少妇一区| 欧美日韩日本网| 欧美国产视频在线观看| 国产私拍一区| 一本大道久久a久久综合婷婷| 国产真实乱偷精品视频免| 亚洲日韩欧美一区二区在线| 好看的亚洲午夜视频在线| 中日韩美女免费视频网站在线观看| 国产一区二区三区自拍| 在线综合亚洲| 99精品国产在热久久婷婷| 久久精品91| 久久国产欧美| 国产欧美日韩亚洲精品| 一本久道综合久久精品| 亚洲精品在线免费| 免费影视亚洲| 欧美不卡在线| 亚洲高清一二三区| 久久综合久久美利坚合众国| 久久久欧美精品sm网站| 国产午夜精品美女毛片视频| 亚洲视频免费看| 亚洲私人黄色宅男| 欧美色视频在线| 99精品视频一区二区三区| 日韩午夜三级在线| 欧美日本高清视频| 日韩视频精品| 亚洲一区在线看| 国产精品美女一区二区在线观看| 亚洲无线一线二线三线区别av| 亚洲性夜色噜噜噜7777| 国产精品高清免费在线观看| 亚洲天堂激情| 午夜欧美大片免费观看| 国产精品一区二区三区久久久 | 在线一区二区日韩| 亚洲亚洲精品在线观看| 欧美亚洲成人精品| 亚洲永久免费av| 久久久成人网| 影音先锋亚洲电影| 猛男gaygay欧美视频| 亚洲国产精品电影| 亚洲婷婷免费| 国产视频一区在线| 久久人人爽人人爽爽久久| 欧美肥婆bbw| av成人毛片| 国产精品毛片va一区二区三区| 亚洲曰本av电影| 免费成人小视频| 一区二区精品| 国产欧美一区二区三区久久| 老司机精品导航| 亚洲精品小视频| 欧美国产日韩xxxxx| 久久久国产精彩视频美女艺术照福利| 国产精品日韩在线| 欧美一区二区大片| 欧美二区乱c少妇| 亚洲在线第一页| 国内精品久久久久影院优| 欧美成年人视频| 亚洲淫性视频| 亚洲国产一区二区三区高清| 香蕉久久夜色精品| 亚洲国产日韩综合一区| 国产精品久久久久7777婷婷| 久久久久国产精品午夜一区| 亚洲卡通欧美制服中文| 久久人人爽爽爽人久久久| 一本大道av伊人久久综合| 国内精品一区二区| 欧美日韩午夜在线视频| 欧美一区二区日韩| 99re热这里只有精品视频| 牛牛精品成人免费视频| 亚洲欧美日韩精品一区二区| 亚洲国产精品久久久久婷婷884| 欧美丝袜一区二区三区| 久久手机免费观看| 亚洲影视在线| 日韩亚洲欧美综合| 欧美护士18xxxxhd| 麻豆成人综合网| 久久爱www| 午夜免费日韩视频| 亚洲夜晚福利在线观看| 亚洲另类一区二区| 亚洲国产综合在线看不卡| 一区免费观看视频| 国产一区二区在线免费观看| 国产精品入口尤物| 国产精品成人一区二区|