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::bind1st,std::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使用原理如下:
-
从std::binary_function派生子类
-
通过bind2nd将派生类和绑定参数绑定到一起,构造binder2nd对象
-
for_each调用仿函数binder2nd对象。
对于为什么会有bind1st和bind2nd之分,是因为有些操作是区分左值和右值的,如:std::less。如果参数更多,怎么办?定义结构体,绑定结构体变量。因为bind支持绑定参数和容器元素类型不同。