关于仿函数很多博客上都有,形式很简单,用途也很多。
一句话总结:重载了()运算符的类可以称之为仿函数functor
现在写一个“比较”
class MyLess{
public:
bool operator()(int a, int b){
return a < b;
}
};
大多数人会这样写,其实这样写没有错,而且基本所有算法都可以通过
比如:
class MyLess{
public:
bool operator()(int a, int b){
return a < b;
}
};
class Less10{
public:
bool operator()(int a){
return a < 10 ? true : false;
}
};
int main() {
vector<int> v{1, 40, 5, 60, 5, 6};
cout<<count_if(v.begin(), v.end(), Less10())<<endl;
sort(v.begin(), v.end(), MyLess());
for(auto i : v)
cout<<i<<" ";
cout<<endl;
}
上面两个仿函数MyLess、Less10。两个算法count_if、sort。
这样的仿函数基本上可以用stl中所有的算法。
看看STL中less怎么写的吧
template <class T>
struct less : public binary_function<T, T, bool> {
bool operator()(const T& x, const T& y) const { return x < y; }
};
除了模板,还有就是less继承了个binary_function,这个是什么鬼?
为什么要继承它?继承它有啥用?
看一个例子:
class MyLess{
public:
bool operator()(int a, int b){
return a < b;
}
};
int main() {
vector<int> v{1, 40, 5, 60, 5, 6};
cout<<count_if(v.begin(), v.end(), bind2nd(less<int>(), 50))<<endl;
}
bind2nd这个叫绑定器,可以绑定一个仿函数的第二个参数。
为啥要使用绑定器?看看第段代码,有没有发现我统计数组中小于10的元素个数太单一了?一点都没有可扩展性,当我们要小于50的时候又得再写一个仿函数,太累了。所以绑定器产生了,现在C++11的绑定都是用bind这个函数(这个函数太厉害了,比bind1nd,bind2nd强大的多,有机会可以去了解下)
回到正题,如果我们把less()换成我们自己写的仿函数,编译就有问题,为啥呢?抛开模板,就是没有继承那个什么鬼了。
看看那个鬼张啥样吧
template <class Arg1, class Arg2, class Result>
struct binary_function {
typedef Arg1 first_argument_type;
typedef Arg2 second_argument_type;
typedef Result result_type;
};
啥?一个成员都木有啊。
其实看STL最大的收获是懂得了typedef的使用,别看简单的一个typedef,几乎在stl中无处不在,绑定器,适配器,萃取器等等,都和typedef密不可分,但是我们正真写程序用typedef的又有几个。
回到正题,我们在看看bind2nd
template <class Operation, class T>
inline binder2nd<Operation> bind2nd(const Operation& op, const T& x) {
typedef typename Operation::second_argument_type arg2_type;
return binder2nd<Operation>(op, arg2_type(x));
}
原来bind2nd要用typedef得到第二参数的类型啊,有啥用?为了检查第二参数是否类型正确,如果转换不了那就直接出错
so,结果就出来了,为啥要继承那个鬼。
再继续看看binder2nd吧
template <class Operation>
class binder2nd
: public unary_function<typename Operation::first_argument_type,
typename Operation::result_type> {
protected:
Operation op;
typename Operation::second_argument_type value;
public:
binder2nd(const Operation& x,
const typename Operation::second_argument_type& y)
: op(x), value(y) {}
result_type operator()(const argument_type& x) const {
return op(x, value);
}
};
这里也需要知道参数类型和返回类型,而且binder2nd本身也是一个仿函数,而且继承了unary_function类
template <class Arg, class Result>
struct unary_function {
typedef Arg argument_type;
typedef Result result_type;
};
到此为止我们可以总结了
仿函数如果要融入STL那么需要继承一个类
一个参数用unary_function
两个参数用binary_function
注意:为啥binary_function有两个参数还是继承unary_function呢?
因为binary_function需要别人推导的只有第一参数而已,第二参数类型已经确定,在本类中已经typedef了