C++如何写adaptable仿函数
2017-12-20 19:47
106 查看
关于仿函数很多博客上都有,形式很简单,用途也很多。
一句话总结:重载了()运算符的类可以称之为仿函数functor
现在写一个“比较”
大多数人会这样写,其实这样写没有错,而且基本所有算法都可以通过
比如:
上面两个仿函数MyLess、Less10。两个算法count_if、sort。
这样的仿函数基本上可以用stl中所有的算法。
看看STL中less怎么写的吧
除了模板,还有就是less继承了个binary_function,这个是什么鬼?
为什么要继承它?继承它有啥用?
看一个例子:
bind2nd这个叫绑定器,可以绑定一个仿函数的第二个参数。
为啥要使用绑定器?看看第段代码,有没有发现我统计数组中小于10的元素个数太单一了?一点都没有可扩展性,当我们要小于50的时候又得再写一个仿函数,太累了。所以绑定器产生了,现在C++11的绑定都是用bind这个函数(这个函数太厉害了,比bind1nd,bind2nd强大的多,有机会可以去了解下)
回到正题,如果我们把less()换成我们自己写的仿函数,编译就有问题,为啥呢?抛开模板,就是没有继承那个什么鬼了。
看看那个鬼张啥样吧
啥?一个成员都木有啊。
其实看STL最大的收获是懂得了typedef的使用,别看简单的一个typedef,几乎在stl中无处不在,绑定器,适配器,萃取器等等,都和typedef密不可分,但是我们正真写程序用typedef的又有几个。
回到正题,我们在看看bind2nd
原来bind2nd要用typedef得到第二参数的类型啊,有啥用?为了检查第二参数是否类型正确,如果转换不了那就直接出错
so,结果就出来了,为啥要继承那个鬼。
再继续看看binder2nd吧
这里也需要知道参数类型和返回类型,而且binder2nd本身也是一个仿函数,而且继承了unary_function类
到此为止我们可以总结了
仿函数如果要融入STL那么需要继承一个类
一个参数用unary_function
两个参数用binary_function
注意:为啥binary_function有两个参数还是继承unary_function呢?
因为binary_function需要别人推导的只有第一参数而已,第二参数类型已经确定,在本类中已经typedef了
一句话总结:重载了()运算符的类可以称之为仿函数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了
相关文章推荐
- 如何禁止C++默认生成成员函数
- C++成员函数如何调用线程
- 如何学好C++
- 关于位域如何节省内存(C++)
- 文件读取C++文件读写操作(三)如何统计文本的行数及如何读取文件某一行内容
- c/c++笔试题——const类型的成员函数内部如何改变成员变量
- 明白在C++中如何使用C
- c/c++中如何更改一个指针值
- C++:在非MFC程序中如何引用CString?
- C++中如何避免资源泄漏
- C++如何导出DLL
- C++调用函数是如何返回临时对象的
- 如何封装c++的指针
- 掌握C/C++之后,如何在Windows系统下开发有界面的程序?
- C++中如何将十进制转化为二进制(使用外部函数)
- 如何理解 C++ 中的深拷贝和浅拷贝?
- c++ istream(ostream)是如何转换为bool的
- 如何找到java对应的c/c++源码
- 你应当如何学习C++ By 刘未鹏(pongba) C++的罗浮宫
- 写给C++初学者,如何开发2D游戏