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中是存在多种适配器的, 下图中包含

  1. 迭代器适配器
  2. 容器适配器
  3. 仿函数适配器

我们这里说仿函数适配器. 那仿函数适配器是干嘛的呢?
仿函数适配器向仿函数提问, 然后仿函数进行回答.
这个功能主要是这样实现的:

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)));
  1. 首先我们知道less<int>()这样是一个对象, 当要调用它时, 其参数是需要两个的;
  2. 后面是一个参数40,
  3. 这两个参数分别作为bind2nd的两个参数, 看下图左上角可知, 我们传入的两个参数会被模板函数自动推断出来(其实bind2nd在这里只是一个辅助函数, 功能就是把类型自动推断出来), 那我们就知道其中op = less<int>(), x = 40了, 然后返回的话就创建一个binder2nd对象. 需要注意的是: 因为x要作为op的第二个参数, 因此返回的时候用arg2_type(x)将x转为arg2_type这种类型了.
  4. 现在我们就到了binder2nd类中了, 先走到构造函数中, 类把x和y分别保存为opvalue, op为操作, value为第二个参数, 然后我们就等待
  5. (先忽略not1)我们现在调用count_if, 传入的参数分别是v1.begin(), v1.end(), 和bind2nd()(这时候bind2nd是一个对象, 但是同时它可以像函数一样被调用), 然后执行到pred(*first)这里, 其实就是执行binder2nd中的()重载函数, 很显然我们看到, 传入的参数只有一个, 就是*first, 然后执行的是less<int>()(x, value) 进行比较, 返回结果

以上这种利用辅助函数来推导类型, 然后函数接着调用另一个类, 类中保存操作方式和一个操作数, 此时还没有调用, 也就还没有绑定, 然后执行算法的时候, 再调用()重载进行调用 的行为, 就被称为函数适配器. (个人理解)


接下来我们说一下not1
其实not1和上面的差不多, 我们接着上面的来: bind2nd之后,

not1(bind2nd...);
  1. 我们首先要知道, bind2nd是一个对象, 因此相当于not1(对象), 这个时候我们就进入not1辅助函数(下图左上角), 返回调用unary_negate类创建对象, 要知道传入的参数是pred, 也就是对象
  2. 现在来到unary_negate类, 继承的是unary_function, 因为需要一个参数, 所以不用binary_function. 接着构造函数将这个对象保存下来
  3. 执行count_if函数, 要知道我们传入的也是一个对象, 一个类名为unar_negate的对象. 在pred(*first)中, 调用对象的()重载函数操作, 函数内部调用类中保存的pred对象, 然后递归调用binder2nd对象, 最后取反.

3. C++11之后出现的新型适配器:bind

以下个人觉得用起来比较麻烦, 仅列举:

用法例子:

C++中的仿函数(functors)和仿函数适配器(adapter function)相关推荐

  1. 仿函数functors

    一.仿函数 仿函数一个class里面重载小括号(),function core operator.仿函数创建的对象是函数对象,是一个对象,像一个函数,function object.仿函数只为算法服务 ...

  2. 【C++ 十九】STL-函数对象(仿函数)、一元谓词、二元谓词、算术仿函数、关系仿函数、逻辑仿函数

    STL-函数对象(仿函数).谓词.内建函数对象 文章目录 STL-函数对象(仿函数).谓词.内建函数对象 前言 1 函数对象 1.1 函数对象概念 1.2 函数对象使用 2 谓词 2.1 谓词概念 2 ...

  3. 设计模式学习笔记——适配器(Adapter)模式

    设计模式学习笔记--适配器(Adapter)模式 @(设计模式)[设计模式, 适配器模式, adapter, 适配器] 设计模式学习笔记适配器Adapter模式 基本介绍 适配器案例 类适配器模式 类 ...

  4. 如何定义适配器adapter类_设计模式22-Adapter(适配器)模式-组件接口适配

    在软件开发过程中,有时候系统的数据和行为都正确,但接口不符合,这时候我们就应该考虑使用适配器模式,适配器的作用即将一个类的接口转换成客户希望的另外一个接口.它使得原本由于接口不兼容而不能一起工作的那些 ...

  5. Ruby设计模式透析之 —— 适配器(Adapter)

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9400153 此为Java设计模式透析的拷贝版,专门为Ruby爱好者提供的,不熟悉R ...

  6. apollo学习基础之三[适配器adapter学习]

    apollo学习基础之三[适配器adapter学习] 目录 apollo学习基础之三[适配器adapter学习] 1.适配封装设计 2. AdapterManager的设计 3.总结归纳: 我们知道, ...

  7. callable object与新增的function相关 C++11中万能的可调用类型声明std::function...

    在c++11中,一个callable object(可调用对象)可以是函数指针.lambda表达式.重载()的某类对象.bind包裹的某对象等等,有时需要统一管理一些这几类对象,新增的function ...

  8. R语言使用mgcv包中的gam函数拟合广义加性模型(Generalized Additive Model,GAMs):从广义加性模型GAM中抽取学习到的样条函数(spline function)

    R语言使用mgcv包中的gam函数拟合广义加性模型(Generalized Additive Model,GAMs):从广义加性模型GAM中抽取学习到的样条函数(spline function) 目录

  9. Java 8 中需要知道的4个函数式接口-Function、Consumer、Supplier、Predicate

    前言 Java 8 中提供了许多函数式接口,包括Function.Consumer.Supplier.Predicate 等等.这 4 个接口就是本篇将要分享的内容,它们都位于 java.util.f ...

  10. Android中ListView的使用以及使用适配器设置数据源

    场景 Android中使用Adapter(适配器)给RecycleView设置数据源: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/detail ...

最新文章

  1. c++ hook 钩子的使用介绍
  2. 北京搜狗已签算法30W,西安银行总包20W,要不要毁约去银行?
  3. 数据中心、智慧机房全套解决方案
  4. Runtime.getRuntime().exec
  5. 数组输出黑科技----fwrite()
  6. 【Canal源码分析】Sink及Store工作过程
  7. MVC上传文件受限制
  8. OSChina 周日乱弹 ——局长才是真神
  9. fetch ajax cros,由 Fetch 跨域 看 CORS
  10. 华为副总裁回应应用删除用户图片;美国拟允许华为参与 5G 标准建设;Firefox 76.0 发布​ | 极客头条...
  11. 不错的 HttpHelper类 c#
  12. 【限时福利】COACKA免费试听@Days China,干货在这里!
  13. numpy_linspace函数
  14. 台式计算机有哪些部分组成,常用台式电脑的基本组成
  15. BUUCTF刷题记录(持续更新中~)
  16. pathogen插件管理器学习笔记
  17. python断点续传下载_Python 3 爬虫|第12章:并发下载大文件 支持断点续传
  18. linux mint安装成功
  19. 让html 自动换行,怎样让HTML 表格中内容自动换行??
  20. 2022年国家自然科学基金指南发布情况

热门文章

  1. 用original绘制重叠柱状图
  2. 2020年度十大高薪岗位出炉,程序员霸榜!
  3. 平均年薪50W+,AI算法岗凭什么?附2020高薪岗位十五强
  4. 编程基础巩固——英语单词记忆技巧
  5. JS初学者使用jQuery开发一款弹幕射击游戏
  6. 【网络】路由器集成锐捷认证
  7. 如何处理给MacBook安装win10双系统时拷贝windows安装文件出错?
  8. 华为php工程师待遇,【博士Offer求比较】211vs华为vs半导体设备商 - 找工作啦(Job)版 - 北大未名BBS...
  9. 利用Greenfoot制作简单的小游戏——记忆翻牌游戏(一)
  10. 闲聊历史上的配角之赵高