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

loop_in_codes

低調(diào)做技術(shù)__歡迎移步我的獨(dú)立博客 codemaro.com 微博 kevinlynx

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

作者:Kevin Lynx

需求:

開發(fā)一種組件,用以包裝C函數(shù)、通常的函數(shù)對象、成員函數(shù),使其對外保持一種一致的接口。我將最終的
組件稱為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)建的對象時,庫會自動將之前bind的參數(shù)傳
遞給bind創(chuàng)建的對象。bind創(chuàng)建出來的對象在某種程度上來說也是一種functor。

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

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

包裝C函數(shù):

思考下各種不同的C函數(shù)的共同點(diǎn)和不同點(diǎn),共同點(diǎn)就是這些函數(shù)都有一個返回值,參數(shù)個數(shù)可能相同,可能
不同,參數(shù)類型可能相同可能不同。考慮到模板對于類型的泛化特性,對于參數(shù)類型來說,可以輕松實(shí)現(xiàn)無
關(guān)性。而至于參數(shù)個數(shù)的泛化,則要復(fù)雜點(diǎn)。這里先考慮實(shí)現(xiàn)參數(shù)個數(shù)為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<intint> cmd( func ); // int func( int )
cmd( 1 );


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

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

}
;


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

包裝函數(shù)對象

要實(shí)現(xiàn)這個目的,其實(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 );
// 測試函數(shù)對象
Func obj;
functor
<intint, Func> cmd2( obj );
cmd2( 
2 );


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

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

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ī)制,使用了動態(tài)內(nèi)存分配(這總會為我們增加麻煩),所以這些,就是為了提供
給用戶一個方便一致的接口。現(xiàn)在我們可以這樣使用functor:

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

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


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

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

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

template <typename _R, >
class functor;


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

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

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

Loki中的魔法:

首先我們要讓functor這個頂層類可以看上去似乎支持可變長度的模板參數(shù)。這個可以通過loki的TypeList實(shí)現(xiàn)。但是
我們這里并不會用到特別復(fù)雜的TypeList技術(shù)。所謂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> >
在實(shí)際實(shí)現(xiàn)時,我們通常會為每一個type list添加一個在loki中叫null_type的類型,就像C字符串末尾的'\0'一樣:
type_list<int, type_list<char, null_type> >
而null_type很簡單,就是一個沒有任何東西的空類型:

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è)計新思維>部分內(nèi)容相同

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

template <typename _R, typename _ParamList>
class functor;


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

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


我們回頭看下之前創(chuàng)建的functor模塊的三個類是如何相互關(guān)聯(lián)的:functor提供給外部用戶接口,handler保存函數(shù)、回調(diào)
函數(shù),handler_base則主要是提供給functor一個可以保存的類型(所以functor里保存的是functor_base)以及聲明各種接口。
為什么需要提供handler_base,而不直接保存handler?因為handler需要保存函數(shù)的類型_FuncType,而這個類型只能在functor構(gòu)造
函數(shù)里被提取出來。局限于這個原因,我加入了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ù)個數(shù)的functor,也就是functor0,functor1等。但是
現(xiàn)在有個很直接的問題,例如當(dāng)functor<void, int>定義了一個參數(shù)時,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就基本實(shí)現(xiàn)了。現(xiàn)在可以這樣使用functor:
沒有參數(shù)的函數(shù): 

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


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

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


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

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

 關(guān)于包裝成員函數(shù),其實(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;
}
;


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

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é)束語:
雖然我們最終的目的實(shí)現(xiàn)了,但是這還是不夠完美。我們還要處理functor的拷貝行為,因為functor天生就是被用來
四處拷貝的。一旦涉及到拷貝,我們就不得不小心翼翼地處理好functor中的那個被new出來的對象。作為一個C++程序員,
你應(yīng)該時刻警惕放在heap上的東西,建立對heap上的警覺感是很重要的。這里我不得不承認(rèn)在后期實(shí)現(xiàn)中,我直接搬了
loki中的很多方案。如果你不想讓這個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)源代碼

 

 

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

評論

# re: 實(shí)現(xiàn)functor - 增強(qiáng)型的函數(shù)指針 2008-03-17 16:43 夢在天涯

functor 確實(shí)是比STL中的一大堆好用多了!統(tǒng)一!  回復(fù)  更多評論   

# re: 實(shí)現(xiàn)functor - 增強(qiáng)型的函數(shù)指針 2008-03-17 16:57 魔域私服

http://www.zhaomysf.com.cn  回復(fù)  更多評論   

# re: 實(shí)現(xiàn)functor - 增強(qiáng)型的函數(shù)指針 2009-07-04 13:47 deadlm

這叫什么東西啊:functor<void, TYPE_LIST2( int, char)>
實(shí)現(xiàn)的非常差勁
就這樣還敢說優(yōu)雅
看到定義個變量跟水蛇一樣長的東西就煩,一個詞評價就是丑陋
等做到functor<void,int,char>再來說優(yōu)雅,這是最基本的實(shí)現(xiàn)要求
  回復(fù)  更多評論   

# re: 實(shí)現(xiàn)functor - 增強(qiáng)型的函數(shù)指針 2009-07-04 17:56 Kevin Lynx

@deadlm
并不見得functor<void, int, char>就比function< void, TYPE_LIST2( int, char )>好。
functor<void, int, char>是需要諸如:
template <typename R, typename P1>
class lua_binder<R ( P1 )>
的語法支持。而并不見得所有的編譯器都支持。另外,我沒有提供這樣的接口也并不見得我寫不出來:
http://m.shnenglu.com/kevinlynx/archive/2008/08/20/59451.html
http://m.shnenglu.com/kevinlynx/archive/2008/08/13/58684.html
另外,這里的TYPE_LIST機(jī)制取自于loki庫。佩服哥們有蔑視loki庫的魄力。  回復(fù)  更多評論   

# re: 實(shí)現(xiàn)functor - 增強(qiáng)型的函數(shù)指針 2009-07-05 14:19 deadlm

首先,我連現(xiàn)在實(shí)現(xiàn)的functor<void, int, char>類型都嫌煩,考慮有沒有更加簡化的實(shí)現(xiàn)方法,這個類的本質(zhì)就是個指針,還要這么多煩雜的東西干嘛
說到編譯器的問題,只要符合c++標(biāo)準(zhǔn)和主要的幾個編譯器沒問題就行,其它的不行那是它本身的實(shí)現(xiàn)有問題,誰能考慮那么多,要有人做個基本編譯不了什么東西的編譯器出來,難道還要顧慮它不成?
任何庫的某個實(shí)現(xiàn)都是可以“蔑視”的,就如更加歷經(jīng)考驗的stl里的string,純粹就是個指針盒,我就自寫了個字符串類代替,而且基本沒在自己的代碼里再用過std::string,只要能兼容它,性能比它更好,犯得著理它嗎  回復(fù)  更多評論   

# re: 實(shí)現(xiàn)functor - 增強(qiáng)型的函數(shù)指針 2009-07-05 14:22 deadlm

還有就是
干嘛要用class lua_binder<R ( P1 )> 這種型式?  回復(fù)  更多評論   

# re: 實(shí)現(xiàn)functor - 增強(qiáng)型的函數(shù)指針 2009-07-05 16:50 Kevin Lynx

@deadlm
functor這種東西本質(zhì)上確實(shí)如你所說是保存一個“函數(shù)”指針。其實(shí)偏要加上返回值類型以及各個參數(shù)的類型,我覺得主要還是哄好編譯器。
void func( int );
void func( int, char );
這兩個函數(shù)在語言層次畢竟屬于不同的類型,functor在回調(diào)他們時,需要知道傳多少個參數(shù)。這些信息都需要保存起來。
template在整個C++中完全屬于一種花哨的東西,當(dāng)然不可否認(rèn)其作用,如果實(shí)在煩這些,可以無視這些語言特性。

之所以我不敢“蔑視”STL、LOKI之類的庫,是因為我自認(rèn)能力沒到這級別。也許以后我可以。

class lua_binder<R ( P1 )> 是lua_binder的偏特化,因為lua_binder本體只有一個類型參數(shù),所以,不能寫:
class lua_binder<R, P1>。這么說來,在支持多參數(shù)函數(shù)的情況下,要么使用functor<int, TYPE_LIST1( ...的形式,要么使用functor<int (int)>的形式。對于functor<int, int>的形式,你指的是怎樣的實(shí)現(xiàn)?(很久沒在弄模板這些東西,有點(diǎn)生疏)。
  回復(fù)  更多評論   

# re: 實(shí)現(xiàn)functor - 增強(qiáng)型的函數(shù)指針 2009-07-05 22:01 deadlm

整個周日下午就在弄這個,終于搞掂,發(fā)現(xiàn)這個實(shí)現(xiàn)用來做事件模型更適當(dāng)

大概因為我最開始選擇的語言是pascal,所以我對cc里聲明個變量就要一長串字符非常厭煩,純粹是長久養(yǎng)成的習(xí)慣。

嗯。。。。。自己看了自己在上面的第一個貼,好像語氣有問題,如果Kevin Lynx 覺得有冒犯,那就不好意思了。  回復(fù)  更多評論   

# re: 實(shí)現(xiàn)functor - 增強(qiáng)型的函數(shù)指針 2009-07-05 22:09 deadlm

其實(shí)加幾個輔助類進(jìn)行記錄就可以不用class lua_binder<R ( P1 )> 的形式,
當(dāng)然這是取巧的作法,你這樣做才是真正實(shí)現(xiàn)無限參數(shù)的方法,而且內(nèi)部實(shí)現(xiàn)的時候看起來會非常丑陋,因為代碼量實(shí)在太多。僅在用起來時看似簡潔。
我以前第一次寫的時候還寫過這樣的東西呢
#define MFuncP(...) LLib::Member_Function_Pointer<__VA_ARGS__>::core_b5_c12  回復(fù)  更多評論   

# re: 實(shí)現(xiàn)functor - 增強(qiáng)型的函數(shù)指針 2009-07-05 22:40 Kevin Lynx

@deadlm
沒用過pascal,不同語言帶來的感受肯定不同。:)

functor之類的東西,為了支持各種不同類型的函數(shù),其內(nèi)部實(shí)現(xiàn)確實(shí)很惡心,而且少不了復(fù)制代碼。后來發(fā)現(xiàn)有宏遞歸這種東西(http://m.shnenglu.com/kevinlynx/archive/2008/08/20/59451.html boost中甚至直接有個macro庫),雖然內(nèi)部實(shí)現(xiàn)可以少寫些代碼(用宏來幫助生成),但是其代碼看起來更糾結(jié)。:D

  回復(fù)  更多評論   

# re: 實(shí)現(xiàn)functor - 增強(qiáng)型的函數(shù)指針 2009-07-05 23:51 deadlm

睡前再說幾句:
我現(xiàn)在實(shí)現(xiàn)的無需聲明參數(shù)函數(shù)指針的內(nèi)部實(shí)現(xiàn)才叫惡心呢,先是用了八九個完全不同的輔助類,然后每個輔助類還重復(fù)了N次,這些還不是最惡心的,最惡心還是因為要進(jìn)行類型弱化,我是直接查詢了模板特化的內(nèi)存序列,硬著上的,那部分代碼我現(xiàn)在看到就有全部選擇然后按下delete鍵的沖動。
只在vc和gcc上試過,還沒在其它編譯測試過,都不知道行不行。

完事后想起一件事,以前用過php,里面的函數(shù)指針好像就是無類型的,是不是應(yīng)該找它的源碼剽上一剽呢?  回復(fù)  更多評論   

# re: 實(shí)現(xiàn)functor - 增強(qiáng)型的函數(shù)指針 2009-07-07 16:13 deadlm

測試過后,終于出問題,不支持返回值為void。。。。。。
結(jié)果只能改成這樣
funcbp fp;
fp.set(testfunc,a);
fp();
本來找到你的blog就是想剽上一剽的。。。。。。。嘿嘿
結(jié)果找了不少地方,你這個還算離我的目的最相近的,其它的很多實(shí)現(xiàn)更離譜
離完全的無類型函數(shù)指針就差一步啊,就因為void不能引用。。。。。。
算了,不折騰了,拜拜
  回復(fù)  更多評論   

# re: 實(shí)現(xiàn)functor - 增強(qiáng)型的函數(shù)指針 2009-07-08 10:30 Kevin Lynx

@deadlm
- -|
  回復(fù)  更多評論   

# re: 實(shí)現(xiàn)functor - 增強(qiáng)型的函數(shù)指針 2010-02-27 16:05 G_cofa

呵呵,好。  回復(fù)  更多評論   

# re: 實(shí)現(xiàn)functor - 增強(qiáng)型的函數(shù)指針 2010-06-02 14:55 欣萌

這是我看過的最好的。  回復(fù)  更多評論   

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            国产精品theporn| 欧美大片免费观看| 国模一区二区三区| 国产毛片久久| 精品盗摄一区二区三区| 在线欧美日韩国产| 一区二区欧美亚洲| 欧美一区二区高清| 美女主播一区| 日韩视频―中文字幕| 亚洲嫩草精品久久| 久久久久久久波多野高潮日日| 久久综合婷婷| 欧美视频一区二区三区在线观看 | 亚洲一区日韩| 欧美一区二粉嫩精品国产一线天| 久久亚洲精品伦理| 亚洲高清在线| 亚洲午夜女主播在线直播| 久久精彩视频| 欧美日韩在线观看视频| 国内外成人免费激情在线视频| 亚洲人成久久| 久久久99久久精品女同性| 亚洲国产精品久久人人爱蜜臀 | 老司机午夜精品视频在线观看| 久久久久久亚洲精品不卡4k岛国| 欧美精品一区二区在线观看| 国产免费成人av| 日韩视频精品在线| 久久综合图片| 亚洲欧美日本精品| 欧美日韩国产系列| 亚洲福利av| 久久久精品日韩欧美| 99爱精品视频| 亚洲一二三区在线| 久久人人看视频| 亚洲色诱最新| 欧美日韩国产一区精品一区| 在线观看欧美精品| 久久精品91久久久久久再现| 日韩亚洲欧美一区| 欧美福利一区二区| 亚洲国产精品成人精品| 久久久另类综合| 亚洲免费影视| 国产精品区二区三区日本| 在线亚洲高清视频| 亚洲激情视频在线| 毛片精品免费在线观看| 加勒比av一区二区| 狂野欧美激情性xxxx欧美| 亚洲欧美日韩一区二区在线 | 亚洲国产另类精品专区| 欧美在线播放一区二区| 一区二区欧美激情| 国产精品hd| 亚洲欧美综合| 亚洲淫性视频| 国产午夜亚洲精品理论片色戒| 先锋亚洲精品| 亚洲一区二区三区涩| 国产精品日本| 久久国产免费看| 久久久www| 18成人免费观看视频| 欧美v国产在线一区二区三区| 久久久www| 亚洲人成人99网站| 亚洲精品中文字幕有码专区| 欧美乱在线观看| 午夜激情综合网| 香蕉久久国产| 亚洲福利国产精品| 亚洲美女视频在线观看| 国产精品麻豆欧美日韩ww| 欧美在线一二三区| 久久一区二区视频| av成人福利| 午夜国产欧美理论在线播放| 国产亚洲欧美另类一区二区三区| 欧美一区免费| 日韩一级大片| 国产精品午夜视频| 久久婷婷麻豆| 欧美国产精品久久| 亚洲一区二区视频在线观看| 亚洲免费在线精品一区| 在线观看不卡| 一区二区三区欧美成人| 黑人极品videos精品欧美裸| 亚洲黄色大片| 国产精品一区久久久| 欧美成人免费在线观看| 欧美日韩一视频区二区| 久久久久久久久久久成人| 欧美超级免费视 在线| 欧美一区二区三区成人 | 欧美破处大片在线视频| 销魂美女一区二区三区视频在线| 久久国产日韩| 亚洲一区精品电影| 久久亚洲精品中文字幕冲田杏梨| 亚洲图片欧洲图片av| 久久免费高清| 香蕉国产精品偷在线观看不卡| 猛干欧美女孩| 久久狠狠亚洲综合| 欧美视频一区二区三区…| 免费中文日韩| 国产欧美日韩综合| 一区二区三区欧美| 亚洲六月丁香色婷婷综合久久| 亚洲欧美国产77777| 一区二区三区福利| 女女同性女同一区二区三区91| 欧美亚洲视频一区二区| 欧美日韩国产天堂| 亚洲第一视频| 在线免费观看日本一区| 午夜精品一区二区三区在线播放| 一区二区三区色| 你懂的国产精品| 欧美成人免费va影院高清| 国产香蕉久久精品综合网| 亚洲淫片在线视频| 亚洲欧美激情视频| 欧美视频1区| 日韩一区二区免费高清| 亚洲最新视频在线| 欧美精品一区二区久久婷婷| 免费成人美女女| 伊人精品成人久久综合软件| 欧美在线高清| 久色成人在线| 原创国产精品91| 另类专区欧美制服同性| 老鸭窝亚洲一区二区三区| 国内精品免费午夜毛片| 久久九九国产| 欧美大片在线观看一区二区| 亚洲第一黄色| 欧美国产免费| 一本色道久久88综合日韩精品 | 欧美国产日韩a欧美在线观看| 亚洲精品少妇| 亚洲网站在线播放| 欧美三级黄美女| 亚洲深夜福利网站| 欧美一区二区三区免费观看| 国产乱码精品一区二区三区忘忧草| 亚洲一区三区电影在线观看| 欧美伊人久久久久久久久影院| 国产日产欧美一区| 久久综合五月| 日韩午夜电影| 香蕉成人伊视频在线观看| 国产亚洲精品久久久久久| 久久精品视频免费观看| 欧美福利影院| 亚洲天堂av高清| 国产视频综合在线| 久久最新视频| 亚洲午夜精品一区二区| 蜜桃久久av| 亚洲午夜女主播在线直播| 国产女人aaa级久久久级| 久久婷婷激情| 一区二区三区欧美在线| 久久久久久免费| aa级大片欧美三级| 好看的日韩视频| 欧美日韩精品一二三区| 欧美一区二区三区喷汁尤物| 欧美黄在线观看| 欧美一级淫片aaaaaaa视频| 亚洲国产婷婷综合在线精品| 国产精品国产精品国产专区不蜜| 久久精品99国产精品日本| 91久久精品国产91性色| 久久黄色网页| 亚洲午夜av电影| 亚洲国产精品va在线看黑人 | 中文在线资源观看网站视频免费不卡| 久久久久国产成人精品亚洲午夜| 亚洲精品综合精品自拍| 国产原创一区二区| 国产精品国产三级国产aⅴ入口| 久久精品人人做人人爽| 在线亚洲欧美视频| 亚洲国产欧美国产综合一区| 久久精品视频在线免费观看| 在线亚洲激情| 亚洲精品专区| 亚洲国产成人精品视频| 国产午夜精品理论片a级大结局| 欧美私人啪啪vps| 欧美精品九九| 免费观看亚洲视频大全|