C++中的仿函数(functors)和仿函数适配器(adapter function)
1. C++标准库中的仿函数例子
比如下面的plus
类, 重载了()
运算符, 可以这样子用plus p; p(1, 2);
, 类可以像调用函数一样的行为, 被称为仿函数.
再看看多几个例子:
然后我们自己写一个仿函数, 然后用sort调用试试:
struct myclass
{bool operator()(int i, int j) { return i < j; }} myobj;//声明一个变量
void test01()
{vector<int> v{1,3,4,2,5,2};sort(v.begin(), v.end(), myobj);for(auto e: v){cout << e << " ";}cout << endl;
}
输出是
1 2 2 3 4 5
但是这里有一个问题,
有没有发现标准库的仿函数都需要继承某个类, 这某个类是下面其中一种:
unary_function
类或者binary_function
类.
而我们的做法没有继承, 这样的不好之处是没有融入到标准库STL中.
那为什么会是不好的呢?
2. 仿函数的可适配(adaptable)条件
如下图, 要知道STL中是存在多种适配器的, 下图中包含
- 迭代器适配器
- 容器适配器
- 仿函数适配器
我们这里说仿函数适配器. 那仿函数适配器是干嘛的呢?
仿函数适配器向仿函数提问, 然后仿函数进行回答.
这个功能主要是这样实现的:
template<typename _Arg, typename _Result>
struct unary_function
{typedef _Arg argument_type;typedef _Result result_type;
};template<typename _Arg1, typename _Arg2, typename _Result>
struct binary_function
{typedef _Arg1 first_argument_type;typedef _Arg2 second_argument_type;typedef _Result result_type;
};
也就是把仿函数的第一个参数, (第二个参数)和返回值类型额外命了名, 方便统一调用.
下面是less的例子:
因为less仿函数有两个参数, 因此继承时需要继承binary_function
.
前面的博客里写了容器适配器, 容器适配器一共额外命名了5个类型, 如下图:
举例stack来说, 它内含deque作为底层容器, 同时需要额外命名5个类型, 这样我们在其他地方用到的时候, 就会很方便(具体例子后面会说)
让我们继续回到函数适配器中,分析一下函数适配器的具体例子:
count_if(v1.begin(), v1.end(), not1(bind2nd(less<int>(), 40)));
- 首先我们知道
less<int>()
这样是一个对象, 当要调用它时, 其参数是需要两个的; - 后面是一个参数
40
, - 这两个参数分别作为
bind2nd
的两个参数, 看下图左上角可知, 我们传入的两个参数会被模板函数自动推断出来(其实bind2nd
在这里只是一个辅助函数, 功能就是把类型自动推断出来), 那我们就知道其中op = less<int>(), x = 40
了, 然后返回的话就创建一个binder2nd
对象. 需要注意的是: 因为x
要作为op
的第二个参数, 因此返回的时候用arg2_type(x)
将x转为arg2_type
这种类型了. - 现在我们就到了
binder2nd
类中了, 先走到构造函数中, 类把x和y分别保存为op
和value
, op为操作, value为第二个参数, 然后我们就等待 - (先忽略not1)我们现在调用
count_if
, 传入的参数分别是v1.begin(), v1.end(), 和bind2nd()
(这时候bind2nd
是一个对象, 但是同时它可以像函数一样被调用), 然后执行到pred(*first)
这里, 其实就是执行binder2nd
中的()
重载函数, 很显然我们看到, 传入的参数只有一个, 就是*first
, 然后执行的是less<int>()(x, value)
进行比较, 返回结果
以上这种利用辅助函数来推导类型, 然后函数接着调用另一个类, 类中保存操作方式和一个操作数, 此时还没有调用, 也就还没有绑定, 然后执行算法的时候, 再调用()
重载进行调用 的行为, 就被称为函数适配器. (个人理解)
接下来我们说一下not1
其实not1
和上面的差不多, 我们接着上面的来: bind2nd
之后,
not1(bind2nd...);
- 我们首先要知道, bind2nd是一个对象, 因此相当于
not1(对象)
, 这个时候我们就进入not1
辅助函数(下图左上角), 返回调用unary_negate
类创建对象, 要知道传入的参数是pred
, 也就是对象 - 现在来到
unary_negate
类, 继承的是unary_function
, 因为需要一个参数, 所以不用binary_function
. 接着构造函数将这个对象保存下来 - 执行
count_if
函数, 要知道我们传入的也是一个对象, 一个类名为unar_negate
的对象. 在pred(*first)
中, 调用对象的()
重载函数操作, 函数内部调用类中保存的pred
对象, 然后递归调用binder2nd
对象, 最后取反.
3. C++11之后出现的新型适配器:bind
以下个人觉得用起来比较麻烦, 仅列举:
用法例子:
C++中的仿函数(functors)和仿函数适配器(adapter function)相关推荐
- 仿函数functors
一.仿函数 仿函数一个class里面重载小括号(),function core operator.仿函数创建的对象是函数对象,是一个对象,像一个函数,function object.仿函数只为算法服务 ...
- 【C++ 十九】STL-函数对象(仿函数)、一元谓词、二元谓词、算术仿函数、关系仿函数、逻辑仿函数
STL-函数对象(仿函数).谓词.内建函数对象 文章目录 STL-函数对象(仿函数).谓词.内建函数对象 前言 1 函数对象 1.1 函数对象概念 1.2 函数对象使用 2 谓词 2.1 谓词概念 2 ...
- 设计模式学习笔记——适配器(Adapter)模式
设计模式学习笔记--适配器(Adapter)模式 @(设计模式)[设计模式, 适配器模式, adapter, 适配器] 设计模式学习笔记适配器Adapter模式 基本介绍 适配器案例 类适配器模式 类 ...
- 如何定义适配器adapter类_设计模式22-Adapter(适配器)模式-组件接口适配
在软件开发过程中,有时候系统的数据和行为都正确,但接口不符合,这时候我们就应该考虑使用适配器模式,适配器的作用即将一个类的接口转换成客户希望的另外一个接口.它使得原本由于接口不兼容而不能一起工作的那些 ...
- Ruby设计模式透析之 —— 适配器(Adapter)
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9400153 此为Java设计模式透析的拷贝版,专门为Ruby爱好者提供的,不熟悉R ...
- apollo学习基础之三[适配器adapter学习]
apollo学习基础之三[适配器adapter学习] 目录 apollo学习基础之三[适配器adapter学习] 1.适配封装设计 2. AdapterManager的设计 3.总结归纳: 我们知道, ...
- callable object与新增的function相关 C++11中万能的可调用类型声明std::function...
在c++11中,一个callable object(可调用对象)可以是函数指针.lambda表达式.重载()的某类对象.bind包裹的某对象等等,有时需要统一管理一些这几类对象,新增的function ...
- R语言使用mgcv包中的gam函数拟合广义加性模型(Generalized Additive Model,GAMs):从广义加性模型GAM中抽取学习到的样条函数(spline function)
R语言使用mgcv包中的gam函数拟合广义加性模型(Generalized Additive Model,GAMs):从广义加性模型GAM中抽取学习到的样条函数(spline function) 目录
- Java 8 中需要知道的4个函数式接口-Function、Consumer、Supplier、Predicate
前言 Java 8 中提供了许多函数式接口,包括Function.Consumer.Supplier.Predicate 等等.这 4 个接口就是本篇将要分享的内容,它们都位于 java.util.f ...
- Android中ListView的使用以及使用适配器设置数据源
场景 Android中使用Adapter(适配器)给RecycleView设置数据源: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/detail ...
最新文章
- c++ hook 钩子的使用介绍
- 北京搜狗已签算法30W,西安银行总包20W,要不要毁约去银行?
- 数据中心、智慧机房全套解决方案
- Runtime.getRuntime().exec
- 数组输出黑科技----fwrite()
- 【Canal源码分析】Sink及Store工作过程
- MVC上传文件受限制
- OSChina 周日乱弹 ——局长才是真神
- fetch ajax cros,由 Fetch 跨域 看 CORS
- 华为副总裁回应应用删除用户图片;美国拟允许华为参与 5G 标准建设;Firefox 76.0 发布​ | 极客头条...
- 不错的 HttpHelper类 c#
- 【限时福利】COACKA免费试听@Days China,干货在这里!
- numpy_linspace函数
- 台式计算机有哪些部分组成,常用台式电脑的基本组成
- BUUCTF刷题记录(持续更新中~)
- pathogen插件管理器学习笔记
- python断点续传下载_Python 3 爬虫|第12章:并发下载大文件 支持断点续传
- linux mint安装成功
- 让html 自动换行,怎样让HTML 表格中内容自动换行??
- 2022年国家自然科学基金指南发布情况
热门文章
- 用original绘制重叠柱状图
- 2020年度十大高薪岗位出炉,程序员霸榜!
- 平均年薪50W+,AI算法岗凭什么?附2020高薪岗位十五强
- 编程基础巩固——英语单词记忆技巧
- JS初学者使用jQuery开发一款弹幕射击游戏
- 【网络】路由器集成锐捷认证
- 如何处理给MacBook安装win10双系统时拷贝windows安装文件出错?
- 华为php工程师待遇,【博士Offer求比较】211vs华为vs半导体设备商 - 找工作啦(Job)版 - 北大未名BBS...
- 利用Greenfoot制作简单的小游戏——记忆翻牌游戏(一)
- 闲聊历史上的配角之赵高