在讲函数对象适配器之前,让我来看看什么是适配器,广义上讲Adaper就是一种将某一接口转换为另一接口的组件。
比如某电器是欧式插头,你怎么插在国标插座上,最直观的想法就是再买个转接器转一下,没错,这个转接器就是一个Adater。
如图(生活中的Adapter)
让我来看之前文章提到的求是否是偶数的even函数,先考虑even就是普通的函数,原型为:
bool even(int x);
现在如果我们要求一个数是否是奇数,你当然可以写一个判别是否是奇数的函数,那么是否可以重用上面的even函数呢?当然可以,如下:
bool odd(int x) {
return !even(x);
}
这也可以看成一个简单的adapter,把原来判别偶数的功能换成了判别奇数,就像上面的插头一样,你可以重换一个插头,也可以买一个转接器,显然后者成本更低,也更灵活。
下面,再让我们看看之前提到的查找第一个偶数的例子:
find_if(f,l,even());
现在我们要查找第一个偶数,同样借鉴上面的想法,我们可以做一个适配器:
template <class Predicate>
class unary_negate {
private:
Predicate pred;
public:
unary_negate(const Predicate& x) : pred(x) {}
bool operator()(const typename Predicate::argument_type& x) const {
return !pred(x);
}
};
可以unary_negate(f)获得一个这样的adapter,但是这样写太麻烦了,我们必须提供函数对象f和类型F,我们可以再包一层:
template <class Predicate>
inline unary_negate<Predicate> not1(Predicate &pre){
return unary_negate<Predicate> (pre);
}
这里利用函数的参数类型推导,那么我们查找奇数就可以写成:find_if(f,l,not1(even()));
这样我们就通过adater服用了even这个函数对象,而不必重新写新的函数对象。
让我们再来看一个例子:
<注:下面例子为了结构清楚,都省略了unary_function和binary_function的继承,实际是有的>
template <class T>
struct less {
bool operator()(const T& x, const T& y) const { return x < y; }
};
显然,less是一个小于比较功能的函数对象;
我们要实现求一个容器中小于某一特定值的元素个数,函数如下:
template <class InputIter, class Predicate, class Size>
void count_if(InputIter first, InputIter last, Predicate pred, Size& n) {
for ( ; first != last; ++first)
if (pred(*first))
++n;
}
显然这里的pred只有一个参数,上面的less有两个参数,怎么通过adater进行重用呢,让我们来看下面的代码:
template <class Operation>
class binder2nd{
public:
binder2nd(const Operation& x, const typename Operation::second_argument_type& y) : op(x), value(y) {}
typename Operation::result_type operator()(const typename Operation::first_argument_type& x) const {
return op(x, value);
}
protected:
Operation op;
typename Operation::second_argument_type value;
};
template <class Operation, class T>
inline binder2nd<Operation> bind2nd(const Operation& fn, const T& x) {
typedef typename Operation::second_argument_type arg2_type;
return binder2nd<Operation>(fn, arg2_type(x));
}
那么,我们就可以通过下面调用得到容器中小于88的元素个数:
count_if(f, l, bind2nd(less_equal(), 88),count);
本文对Adapter做了简单探讨,Mark。