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支持绑定参数和容器元素类型不同。


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