在《STL源码剖析》一书的第7章第2节提到,binary_function用来呈现二元函数的第一参数类型、第二参数类型,以及返回值类型,定义如下:
// STL规定,每一个Adaptable Binary Function都应继承此类别
template <class Arg1, class Arg2, class Result>
struct Binary_function {
typedef Arg1 first_argument_type;
typedef Arg2 second_argument_type;
typedef Result result_type;
}
一旦某个仿函数继承了它,其用户便可以这样取得该仿函数的各种相应类型
// 以下仿函数继承了binary_function
template <class T>
struct plus : public binary_function<T, T, T> {
T operator()(const T& x, const T& y, ) const {
return x + y;
}
};
// 以下配接器将二元仿函数转化为一元仿函数
template <class Operation>
class binder1st : public unary_function<typename Operation::second_argument_type, typename Operation::result_type> {
protected:
Operation op;
typename Operation::first_argument_type value;
public:
binder1st(const Operation& x, const typename Operation::first_argument_type& y) : op(x), value(y) {}
typename Operation::result_type operator()(const Operation::second_argument_type& a) const {
return op(value, a);
}
};
// 根据构造函数的定义,以上该函数的目的是将Operation函数的第一个参数绑定到一个值,该值是在调用binder1st时设定的,
// 然后因为重载了operator(),因此在调用binder1st对象时,被传入的参数会被当做Operation函数的第二个参数,
// 第一个参数已经固定为上文的value,也就是return op(value, a)中的value
实例分析: 现在要对一个vector中的每一个元素施行策略:(x + 2) * 3,可以这么写:
std::vector<int> v{1, 2, 3};
std::for_each(v.begin(), v.end(), compose1(bind2nd(multiplies<int>(), 3), bind2nd(plus<int>(), 2)));
// 解释
bind2nd 与上面的binder1st类似,是绑定第二个参数为设定的值,比如上文中的3 和 2.
比如bind2nd(plus<int>(), 2) ,plus 函数对象的第二个参数为2,同时bind2nd会将该二元函数转为一元函数:
typename Operation::result_type operator()(const Operation::first_argument_type& a) const {
return op(a, value);
}
// a固定为2,value是通过调用该函数对象时传入的值,在这里就是vector的每一个元素
// 最终bind2nd(plus<int>(), 2)等效于 x + 2
// compose1的意思是先执行后一个表达式,得到的结果代入前一个表达式,因此这里的compose1即为 (x + 2) * 3
compose1源码如下,位于stl_function.h中:
template <class _Operation1, class _Operation2>
class unary_compose
: public unary_function<typename _Operation2::argument_type,
typename _Operation1::result_type>
{
protected:
_Operation1 _M_fn1;
_Operation2 _M_fn2;
public:
unary_compose(const _Operation1& __x, const _Operation2& __y)
: _M_fn1(__x), _M_fn2(__y) {}
typename _Operation1::result_type
operator()(const typename _Operation2::argument_type& __x) const {
return _M_fn1(_M_fn2(__x));
}
};
template <class _Operation1, class _Operation2>
inline unary_compose<_Operation1,_Operation2>
compose1(const _Operation1& __fn1, const _Operation2& __fn2)
{
return unary_compose<_Operation1,_Operation2>(__fn1, __fn2);
}