博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
仿函数可配接性探讨
阅读量:5246 次
发布时间:2019-06-14

本文共 3656 字,大约阅读时间需要 12 分钟。

前言

仿函数的可配接性是指仿函数能够与其它仿函数配接在一起实现新的功能,如不小于60,该需求可以利用STL自带的not1<int>和less<int>配接而成,代码实现如下:

not1(bind2nd(less
(), 60))

但是有时又需要我们自定义仿函数,又或者类成员函数与仿函数绑定、一般函数与仿函数一起绑定等,针对这些场景STL给出了额外的函数配接器或者给出技术要求,博文中就介绍了STL额外的两种函数配接器,包括成员函数配接器,一般函数配接器,这两种函数配接器的实现原理bind2nd大致相当,核心都进行了operator()重载操作

“可配接性”分析

为了能够达到可配接性,就必须提供型别成员(type member) 来反映其参数和返回值;STL提供了binary_function,unary_function这两个结构体;它们具体结构如下:

// TEMPLATE STRUCT unary_functiontemplate
struct unary_function{ // base class for unary functions typedef _Arg argument_type; typedef _Result result_type;};// TEMPLATE STRUCT binary_functiontemplate
struct binary_function{ // base class for binary functions typedef _Arg1 first_argument_type; typedef _Arg2 second_argument_type; typedef _Result result_type;};

这两个结构通过模板技术在内部进行了型别的重命名,STL预定的仿函数都继承于这两个结构体,因此预定义的仿函数就获得了用户指定的类型,因此预定义的仿函数都具备“可配接性”。若我们自定义的仿函数需要和函数配接器结合,也必须继承这两者之一;

bind2nd原理剖析

我们以如下代码分析bind2nd的实现过程:

int nNumber1 = count_if(Container.begin(),                            Container.end(),                           bind2nd(less
(), 60));

在配接器bind2nd中,参数1是less<int>() 生成仿函数对象副本,其参数是int类型;参数2是value60;

less源码如下:

template
struct less: public binary_function<_Ty, _Ty, bool>{ // functor for operator< bool operator()(const _Ty& _Left, const _Ty& _Right) const { // apply operator< to operands return (_Left < _Right); }};

仿函数less继承于binary_function模板,并将less的比较类型传递给了binary_function模板,在binary_function模板类中对_Arg1,_Arg2进行了类型重命名,分别是first_argument_type 和second_argument_type,这里都是int类型,和less模板参数一致,result_type是bool类型。

bind2nd源码如下:

// TEMPLATE FUNCTION bind2ndtemplate
inlinebinder2nd<_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));}

在bind2nd函数体内定义了临时变量_Val并初始化,其类型是仿函数less中定义的second_argument_type,也就是int类型,配接器函数bind2nd返回值是仿函数binder2nd对象副本,其成员是less functor和value 60;

binderd2nd的实现如下:

// TEMPLATE CLASS binder2ndtemplate
class binder2nd: public unary_function
{ // functor adapter _Func(left, stored)public: typedef unary_function
_Base; typedef typename _Base::argument_type argument_type; typedef typename _Base::result_type result_type;binder2nd(const _Fn2& _Func, const typename _Fn2::second_argument_type& _Right):op(_Func), value(_Right) { // construct from functor and right operand }result_type operator()(const argument_type& _Left) const { // apply functor to operands return (op(_Left, value));//返回less仿函数临时对象 }result_type operator()(argument_type& _Left) const { // apply functor to operands return (op(_Left, value));//返回less仿函数临时对象 }protected: _Fn2 op; // the functor to apply 返回值是是仿函数对象即less仿函数 typename _Fn2::second_argument_type value; // the right operand};

现在分析count_if的实现,源码如下:

template
inlinetypename iterator_traits<_InIt>::difference_type_Count_if(_InIt _First, _InIt _Last, _Pr _Pred){ // count elements satisfying _Pred typename iterator_traits<_InIt>::difference_type _Count = 0; for (; _First != _Last; ++_First) { if (_Pred(*_First))//调用binder2nd中的operator()函数 { ++_Count; } } return (_Count);}
_Pred是仿函数binder2nd的副本,_Pred(*_First)会调用binder2nd的operator(), op是less仿函数对象,第一参数是容器中的元素,第二个参数是60,count_if会对每一元素都做一遍判断,从而统计符合要求的元素个数。

bind2nd原理地图

下图展示了bind2nd配接器实现过程,如何完成仿函数和仿函数的配接过程。

Step1:将仿函数less和value 60固化到仿函数binder2nd内部,称为仿函数binder2nd的成员函数

Step2:bind2nd函数返回binder2nd的对象,并传递给count_if算法,称为第三个参数

Step3:在count_if()算法内部调用binder2nd operater()实现,从而完成符合要求的数据统计

转载于:https://www.cnblogs.com/jinxiang1224/p/8468409.html

你可能感兴趣的文章
51nod1076 (边双连通)
查看>>
Item 9: Avoid Conversion Operators in Your APIs(Effective C#)
查看>>
学习Spring Boot:(二十八)Spring Security 权限认证
查看>>
深入浅出JavaScript(2)—ECMAScript
查看>>
STEP2——《数据分析:企业的贤内助》重点摘要笔记(六)——数据描述
查看>>
ViewPager的onPageChangeListener里面的一些方法参数:
查看>>
Jenkins关闭、重启,Jenkins服务的启动、停止方法。
查看>>
CF E2 - Array and Segments (Hard version) (线段树)
查看>>
Linux SPI总线和设备驱动架构之四:SPI数据传输的队列化
查看>>
SIGPIPE并产生一个信号处理
查看>>
CentOS
查看>>
Linux pipe函数
查看>>
java equals 小记
查看>>
爬虫-通用代码框架
查看>>
2019春 软件工程实践 助教总结
查看>>
YUV 格式的视频呈现
查看>>
Android弹出框的学习
查看>>
现代程序设计 作业1
查看>>
在android开发中添加外挂字体
查看>>
Zerver是一个C#开发的Nginx+PHP+Mysql+memcached+redis绿色集成开发环境
查看>>