仿函数(functors)其实就是重载了operator()的对象。

下面简单先看看它的一个例子:

  1. #include <iostream>
  2. using namespace std;
  3.  
  4. template<typename T>
  5. struct m_plus
  6. {
  7. T operator()(const T& x, const T& y) { return x + y; }
  8. };
  9.  
  10. int main(int argc, char *argv[])
  11. {
  12. // 定义其对象 调用其operator()
  13. m_plus<int> op;
  14. cout << op(, ) << endl;
  15. // 产生一个匿名对象 这是仿函数的主流用法
  16. cout << m_plus<int>()(, ) << endl;
  17. return ;
  18. }

既然仿函数跟函数的用法类同,那为什么不直接使用函数指针代替呢?

个人认为有两个原因

1.仿函数可以有自己的状态,而函数指针则不行(有的使用template或者static变量可以实现)。

我们可以这样子使用仿函数:

  1. #include <iostream>
  2. using namespace std;
  3.  
  4. template<typename T, T add>
  5. struct m_plus
  6. {
  7. m_plus() { _add = add; }
  8. T operator()(const T& x) { return x + _add; }
  9. // 仿函数可以具有自己的状态
  10. int _add;
  11. };
  12.  
  13. int main(int argc, char *argv[])
  14. {
  15. m_plus<int, > op;
  16. cout << op() << endl;
  17. cout << op() << endl;
  18. return ;
  19. }

2.仿函数可以与函数适配器搭配使用。

举一个例子,例如我们如果要使用count_if算法来计算容器中大于10的元素的个数。

如果我们使用greater<int>作为判别式(二元),而count_if只接受一个一元判别式,这时候我们就需要搭配函数适配器一起使用了。

而函数指针不能直接搭配函数适配器一起使用,具体在分析bind2nd的时候会讲到。

  1. #include <iostream>
  2. #include <vector>
  3. #include <functional>
  4. #include <algorithm>
  5. using namespace std;
  6.  
  7. int main(int argc, char *argv[])
  8. {
  9. vector<int> coll{ , , , , , , , };
  10. // 接着下面有bind2nd的具体实现
  11. cout << count_if(coll.begin(), coll.end(), bind2nd(greater<int>(), )) << endl;
  12. return ;
  13. }

bind2nd

bind2nd可以将二元仿函数转化为一元仿函数,这看上去好像很神奇,其实它的实现很简单。

首先,二元仿函数会继承自binary_function,其实只是一些typedef,这些都将用于函数适配器。

  1. template <class Arg1, class Arg2, class Result>
  2. struct binary_function {
  3. typedef Arg1 first_argument_type;
  4. typedef Arg2 second_argument_type;
  5. typedef Result result_type;
  6. };
  7.  
  8. template <class T>
  9. struct greater : public binary_function<T, T, bool> {
  10. bool operator()(const T& x, const T& y) const { return x > y; }
  11. };

bind2nd将二元仿函数跟第二个参数型别作为模板型别,下面是具体实现:

  1. template <class Operation, class T>
  2. inline binder2nd<Operation> bind2nd(const Operation& op, const T& x) {
  3. typedef typename Operation::second_argument_type arg2_type;
  4. // 调用binder2nd
  5. return binder2nd<Operation>(op, arg2_type(x));
  6. }
  7.  
  8. // binder2nd是一个一元仿函数(本身可以搭配函数适配器一起使用)
  9. template <class Operation>
  10. class binder2nd
  11. : public unary_function<typename Operation::first_argument_type,
  12. typename Operation::result_type>
  13. {
  14. protected:
  15. // 传进来的二元仿函数
  16. Operation op;
  17. // 传进来的第二个参数 因为仿函数内部可以typedef 而函数指针则不行
  18. // 因此只能适配仿函数 而不能适配函数指针
  19. typename Operation::second_argument_type value;
  20. public:
  21. // 构造函数
  22. binder2nd(const Operation& x,
  23. const typename Operation::second_argument_type& y)
  24. : op(x), value(y) {}
  25.  
  26. // 直接调用二元仿函数
  27. typename Operation::result_type
  28. operator()(const typename Operation::first_argument_type& x) const {
  29. return op(x, value);
  30. }
  31. };

STL源码剖析(仿函数/bind2nd)的更多相关文章

  1. STL"源码"剖析-重点知识总结

    STL是C++重要的组件之一,大学时看过<STL源码剖析>这本书,这几天复习了一下,总结出以下LZ认为比较重要的知识点,内容有点略多 :) 1.STL概述 STL提供六大组件,彼此可以组合 ...

  2. 【转载】STL"源码"剖析-重点知识总结

    原文:STL"源码"剖析-重点知识总结 STL是C++重要的组件之一,大学时看过<STL源码剖析>这本书,这几天复习了一下,总结出以下LZ认为比较重要的知识点,内容有点 ...

  3. STL"源码"剖析

    STL"源码"剖析-重点知识总结   STL是C++重要的组件之一,大学时看过<STL源码剖析>这本书,这几天复习了一下,总结出以下LZ认为比较重要的知识点,内容有点略 ...

  4. 《STL源码剖析》相关面试题总结

    原文链接:http://www.cnblogs.com/raichen/p/5817158.html 一.STL简介 STL提供六大组件,彼此可以组合套用: 容器容器就是各种数据结构,我就不多说,看看 ...

  5. 《STL源码剖析》读书笔记

    转载:https://www.cnblogs.com/xiaoyi115/p/3721922.html 直接逼入正题. Standard Template Library简称STL.STL可分为容器( ...

  6. STL源码剖析之组件

    本篇文章开始,进行STL源码剖析的一些知识点,后续系列笔记全是参照<STL源码剖析>进行学习记录的 STL在现在的大部分项目中,实用性已经没有Boost库好了,毕竟STL中仅仅提供了一些容 ...

  7. 面试题总结(三)、《STL源码剖析》相关面试题总结

    声明:本文主要探讨与STL实现相关的面试题,主要参考侯捷的<STL源码剖析>,每一个知识点讨论力求简洁,便于记忆,但讨论深度有限,如要深入研究可点击参考链接,希望对正在找工作的同学有点帮助 ...

  8. 通读《STL源码剖析》之后的一点读书笔记

    直接逼入正题. Standard Template Library简称STL.STL可分为容器(containers).迭代器(iterators).空间配置器(allocator).配接器(adap ...

  9. 0《STL源码剖析》简介

    STL源码剖析 ----侯捷 STL主要包括六个组件: 1.配置器:负责空间配置和管理. 2.迭代器:扮演容器和算法之前的胶合剂,所谓“泛型指针”. 3.容器:各种数据结构,如vector,list, ...

随机推荐

  1. ServletContext (上下文对象)

    一.什么是ServletContext ServletContext代表是一个web应用的上下文对象(web应用对象) 里面封装的都是web应用信息 一个ServletContext对应一个应用 二. ...

  2. 【预处理】【分类讨论】Playrix Codescapes Cup (Codeforces Round #413, rated, Div. 1 + Div. 2) C. Fountains

    分几种情况讨论: (1)仅用C或D买两个 ①买两个代价相同的(实际不同)(排个序) ②买两个代价不同的(因为买两个代价相同的情况已经考虑过了,所以此时对于同一个代价,只需要保存美丽度最高的喷泉即可)( ...

  3. 【后缀自动机】hihocoder1449 后缀自动机三·重复旋律6

    解题方法提示 小Hi:上次我们已经学习了后缀自动机了,今天我们再来解决一个用到后缀自动机的问题. 小Ho:好!那我们开始吧! 小Hi:现在我们要对K=1..length(S)求出所有长度为K的子串中出 ...

  4. 【状态压缩DP】NOIP2005-river过河

    [问题描述] 在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧.在桥上有一些石子,青蛙很讨厌踩在这些石子上.由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙可能到达的点看 ...

  5. 协程和IO模型

    协程 1.什么是协程 单线程实现并发 在应用程序里控制多个任务的切换+保存状态 优点: 应用程序级别速度要远远高于操作系统的切换 缺点: 多个任务一旦有一个阻塞没有切,整个线程都阻塞在原地 该线程内的 ...

  6. Html 事件列表

    Html 事件列表 一般事件:onClick HTML: 鼠标点击事件,多用在某个对象控制的范围内的鼠标点击onDblClick HTML: 鼠标双击事件onMouseDown HTML: 鼠标上的按 ...

  7. SQL Server--CheckPoint

    http://www.cnblogs.com/TeyGao/category/526201.html

  8. 怎样打开查看mysql binlog

    1 在my.ini(window)配置文件里面 [mysqld]log-bin=mysql-bin(名字可以随便起) 我们每次进行操作的时候,File_size都会增长 2.show binlog e ...

  9. C++ Java C#泛型

    泛型概述C#中的泛型C#泛型和java泛型的比较C#泛型和C++模板的比较C#泛型中的约束 泛型概述 Bruce Eckel :您能对泛型做一个快速的介绍么? Anders Hejlsberg : 泛 ...

  10. hive如何使用中文查询条件

    直接在hql中使用中文会报错:org.apache.hadoop.ipc.RemoteException: java.io.IOException: java.lang.RuntimeExceptio ...