stdbind剖析

stl算法庫多數算法只能提供一個參數給綁定函數,如for_each函數。如果想打印vector中的每一個元素,用for_each實現方式代碼如下:

#include <iostream>

#include <algorithm>

#include <vector>

 

struct print

{

         voidoperator()(const int x){     std::cout<< x << std::endl; }

};

 

int main(int argc, char **argv)

{

         std::vector<int>vec{ 1, 3, 5, 7, 9 };

         std::for_each(vec.begin(),vec.end(), print());

 

         return0;

}

但如果綁定函數要求有兩個,或多個輸入參數呢?例如,想對vector中的每個元素值增加100,很明顯,僅僅靠for_each算法提供的一個參數無法實現。因此,需要給綁定函數增加一個成員變量,代碼實現如下:

#include <iostream>

#include <algorithm>

#include <vector>

 

struct print

{

         voidoperator()(const int x) {    std::cout<< x << std::endl; }

};

 

struct add

{

         inti;

         add(int_i) : i(_i) {}

         intoperator()(int &x) { x += i; return x; }

};

 

int main(int argc, char **argv)

{

         std::vector<int>vec{ 1, 3, 5, 7, 9 };

         std::for_each(vec.begin(),vec.end(), print());

         std::for_each(vec.begin(),vec.end(),  add(100));

         std::for_each(vec.begin(),vec.end(), print());

 

         return0;

}

除了上面的方式,還可以使用std::bind1ststd::bind2nd,使用std::bind2nd代碼如下:

#include <iostream>

#include <string>

#include <algorithm> //std::for_each

#include <xfunctional> //std::bind2nd

#include <vector>

 

struct print

{

         voidoperator()(const int x)

         {

                   std::cout<< x << std::endl;

         }

};

 

 

struct add : public std::binary_function< int, int, int >

{

         intoperator()(int &x, const int &y) const {      x += y; return x; } //必須爲const函數

};

 

int main(int argc, char **argv)

{

         std::vector<int>vec{ 1, 3, 5, 7, 9 };

         std::for_each(vec.begin(),vec.end(), print());

         std::for_each(vec.begin(),vec.end(), std::bind2nd(add(), 100));

         std::for_each(vec.begin(),vec.end(), print());

 

         return0;

}

注意add()(函數操作符)操作符必須爲const函數,否則會出現下面的錯誤:

errorC3848: 具有類型“const add”的表達式會丟失一些 const-volatile 限定符以調用“int add::operator ()(int &,const int &)

std::bind是如何將100綁定到第二個參數的呢?先看看std::binary_function,實現如下:

template<class _Arg1,

         class_Arg2,

         class_Result>

         structbinary_function

         {        // base class for binary functions

         typedef_Arg1 first_argument_type;

         typedef_Arg2 second_argument_type;

         typedef_Result result_type;

         };

不難發現該類僅定義了三個類型,第一個參數類型,第二個參數類型,返回值類型。這三個類型到底有什麼作用呢?再看看std::bind2nd實現:

template<class _Fn2,

         class_Ty> inline

         binder2nd<_Fn2>bind2nd(const _Fn2& _Func, const _Ty& _Right)

         {        // return a binder2nd functor adapter

         typename_Fn2::second_argument_type _Val(_Right);

         return(_STD binder2nd<_Fn2>(_Func, _Val));

         }

_Fn2實際就是傳入的仿函數類型binary_function的派生類,裏面用到了second_argument_type(綁定參數類型),並通過_Fn2對象和綁定參數構建了一個binder2nd對象,binder2nd實現如下:

template<class _Fn2>

         classbinder2nd

                   :public unary_function<typename _Fn2::first_argument_type,

                            typename_Fn2::result_type>

         {        // functor adapter _Func(left, stored)

public:

         typedefunary_function<typename _Fn2::first_argument_type,

                   typename_Fn2::result_type> _Base;

         typedeftypename _Base::argument_type argument_type;

         typedeftypename _Base::result_type result_type;

 

         binder2nd(const_Fn2& _Func,

                   consttypename _Fn2::second_argument_type& _Right)

                   :op(_Func), value(_Right)

                   {        // construct from functor and rightoperand

                   }

 

         result_typeoperator()(const argument_type& _Left) const

                   {        // apply functor to operands

                   return(op(_Left, value));

                   }

 

         result_typeoperator()(argument_type& _Left) const

                   {        // apply functor to operands

                   return(op(_Left, value));

                   }

 

protected:

         _Fn2op;   // the functor to apply

         typename_Fn2::second_argument_type value;    //the right operand

         };

binder2nd保存仿函數對象op,和綁定參數,並重載函數操作符,函數操作符均有一個參數,即容器元素,其類型爲argument_fisrt_type。在操作符調用op(容器元素, 綁定參數),其原理和帶成員變量i的仿函數一樣。binder2nd的基類unary_function實現也很簡單:

template<class _Arg,

         class_Result>

         structunary_function

         {        // base class for unary functions

         typedef_Arg argument_type;

         typedef_Result result_type;

         };

該類僅僅定義了返回類型和參數類型(for_each傳入參數)。

bind2nd使用原理如下:

  1. std::binary_function派生子類

  2. 通過bind2nd將派生類和綁定參數綁定到一起,構造binder2nd對象

  3. for_each調用仿函數binder2nd對象。

對於爲什麼會有bind1stbind2nd之分,是因爲有些操作是區分左值和右值的,如:std::less。如果參數更多,怎麼辦?定義結構體,綁定結構體變量。因爲bind支持綁定參數和容器元素類型不同。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章