STL源码剖析(仿函数/bind2nd)
仿函数(functors)其实就是重载了operator()的对象。
下面简单先看看它的一个例子:
- #include <iostream>
- using namespace std;
- template<typename T>
- struct m_plus
- {
- T operator()(const T& x, const T& y) { return x + y; }
- };
- int main(int argc, char *argv[])
- {
- // 定义其对象 调用其operator()
- m_plus<int> op;
- cout << op(, ) << endl;
- // 产生一个匿名对象 这是仿函数的主流用法
- cout << m_plus<int>()(, ) << endl;
- return ;
- }
既然仿函数跟函数的用法类同,那为什么不直接使用函数指针代替呢?
个人认为有两个原因
1.仿函数可以有自己的状态,而函数指针则不行(有的使用template或者static变量可以实现)。
我们可以这样子使用仿函数:
- #include <iostream>
- using namespace std;
- template<typename T, T add>
- struct m_plus
- {
- m_plus() { _add = add; }
- T operator()(const T& x) { return x + _add; }
- // 仿函数可以具有自己的状态
- int _add;
- };
- int main(int argc, char *argv[])
- {
- m_plus<int, > op;
- cout << op() << endl;
- cout << op() << endl;
- return ;
- }
2.仿函数可以与函数适配器搭配使用。
举一个例子,例如我们如果要使用count_if算法来计算容器中大于10的元素的个数。
如果我们使用greater<int>作为判别式(二元),而count_if只接受一个一元判别式,这时候我们就需要搭配函数适配器一起使用了。
而函数指针不能直接搭配函数适配器一起使用,具体在分析bind2nd的时候会讲到。
- #include <iostream>
- #include <vector>
- #include <functional>
- #include <algorithm>
- using namespace std;
- int main(int argc, char *argv[])
- {
- vector<int> coll{ , , , , , , , };
- // 接着下面有bind2nd的具体实现
- cout << count_if(coll.begin(), coll.end(), bind2nd(greater<int>(), )) << endl;
- return ;
- }
bind2nd
bind2nd可以将二元仿函数转化为一元仿函数,这看上去好像很神奇,其实它的实现很简单。
首先,二元仿函数会继承自binary_function,其实只是一些typedef,这些都将用于函数适配器。
- template <class Arg1, class Arg2, class Result>
- struct binary_function {
- typedef Arg1 first_argument_type;
- typedef Arg2 second_argument_type;
- typedef Result result_type;
- };
- template <class T>
- struct greater : public binary_function<T, T, bool> {
- bool operator()(const T& x, const T& y) const { return x > y; }
- };
bind2nd将二元仿函数跟第二个参数型别作为模板型别,下面是具体实现:
- template <class Operation, class T>
- inline binder2nd<Operation> bind2nd(const Operation& op, const T& x) {
- typedef typename Operation::second_argument_type arg2_type;
- // 调用binder2nd
- return binder2nd<Operation>(op, arg2_type(x));
- }
- // binder2nd是一个一元仿函数(本身可以搭配函数适配器一起使用)
- template <class Operation>
- class binder2nd
- : public unary_function<typename Operation::first_argument_type,
- typename Operation::result_type>
- {
- protected:
- // 传进来的二元仿函数
- Operation op;
- // 传进来的第二个参数 因为仿函数内部可以typedef 而函数指针则不行
- // 因此只能适配仿函数 而不能适配函数指针
- typename Operation::second_argument_type value;
- public:
- // 构造函数
- binder2nd(const Operation& x,
- const typename Operation::second_argument_type& y)
- : op(x), value(y) {}
- // 直接调用二元仿函数
- typename Operation::result_type
- operator()(const typename Operation::first_argument_type& x) const {
- return op(x, value);
- }
- };
STL源码剖析(仿函数/bind2nd)的更多相关文章
- STL"源码"剖析-重点知识总结
STL是C++重要的组件之一,大学时看过<STL源码剖析>这本书,这几天复习了一下,总结出以下LZ认为比较重要的知识点,内容有点略多 :) 1.STL概述 STL提供六大组件,彼此可以组合 ...
- 【转载】STL"源码"剖析-重点知识总结
原文:STL"源码"剖析-重点知识总结 STL是C++重要的组件之一,大学时看过<STL源码剖析>这本书,这几天复习了一下,总结出以下LZ认为比较重要的知识点,内容有点 ...
- STL"源码"剖析
STL"源码"剖析-重点知识总结 STL是C++重要的组件之一,大学时看过<STL源码剖析>这本书,这几天复习了一下,总结出以下LZ认为比较重要的知识点,内容有点略 ...
- 《STL源码剖析》相关面试题总结
原文链接:http://www.cnblogs.com/raichen/p/5817158.html 一.STL简介 STL提供六大组件,彼此可以组合套用: 容器容器就是各种数据结构,我就不多说,看看 ...
- 《STL源码剖析》读书笔记
转载:https://www.cnblogs.com/xiaoyi115/p/3721922.html 直接逼入正题. Standard Template Library简称STL.STL可分为容器( ...
- STL源码剖析之组件
本篇文章开始,进行STL源码剖析的一些知识点,后续系列笔记全是参照<STL源码剖析>进行学习记录的 STL在现在的大部分项目中,实用性已经没有Boost库好了,毕竟STL中仅仅提供了一些容 ...
- 面试题总结(三)、《STL源码剖析》相关面试题总结
声明:本文主要探讨与STL实现相关的面试题,主要参考侯捷的<STL源码剖析>,每一个知识点讨论力求简洁,便于记忆,但讨论深度有限,如要深入研究可点击参考链接,希望对正在找工作的同学有点帮助 ...
- 通读《STL源码剖析》之后的一点读书笔记
直接逼入正题. Standard Template Library简称STL.STL可分为容器(containers).迭代器(iterators).空间配置器(allocator).配接器(adap ...
- 0《STL源码剖析》简介
STL源码剖析 ----侯捷 STL主要包括六个组件: 1.配置器:负责空间配置和管理. 2.迭代器:扮演容器和算法之前的胶合剂,所谓“泛型指针”. 3.容器:各种数据结构,如vector,list, ...
随机推荐
- ServletContext (上下文对象)
一.什么是ServletContext ServletContext代表是一个web应用的上下文对象(web应用对象) 里面封装的都是web应用信息 一个ServletContext对应一个应用 二. ...
- 【预处理】【分类讨论】Playrix Codescapes Cup (Codeforces Round #413, rated, Div. 1 + Div. 2) C. Fountains
分几种情况讨论: (1)仅用C或D买两个 ①买两个代价相同的(实际不同)(排个序) ②买两个代价不同的(因为买两个代价相同的情况已经考虑过了,所以此时对于同一个代价,只需要保存美丽度最高的喷泉即可)( ...
- 【后缀自动机】hihocoder1449 后缀自动机三·重复旋律6
解题方法提示 小Hi:上次我们已经学习了后缀自动机了,今天我们再来解决一个用到后缀自动机的问题. 小Ho:好!那我们开始吧! 小Hi:现在我们要对K=1..length(S)求出所有长度为K的子串中出 ...
- 【状态压缩DP】NOIP2005-river过河
[问题描述] 在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧.在桥上有一些石子,青蛙很讨厌踩在这些石子上.由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙可能到达的点看 ...
- 协程和IO模型
协程 1.什么是协程 单线程实现并发 在应用程序里控制多个任务的切换+保存状态 优点: 应用程序级别速度要远远高于操作系统的切换 缺点: 多个任务一旦有一个阻塞没有切,整个线程都阻塞在原地 该线程内的 ...
- Html 事件列表
Html 事件列表 一般事件:onClick HTML: 鼠标点击事件,多用在某个对象控制的范围内的鼠标点击onDblClick HTML: 鼠标双击事件onMouseDown HTML: 鼠标上的按 ...
- SQL Server--CheckPoint
http://www.cnblogs.com/TeyGao/category/526201.html
- 怎样打开查看mysql binlog
1 在my.ini(window)配置文件里面 [mysqld]log-bin=mysql-bin(名字可以随便起) 我们每次进行操作的时候,File_size都会增长 2.show binlog e ...
- C++ Java C#泛型
泛型概述C#中的泛型C#泛型和java泛型的比较C#泛型和C++模板的比较C#泛型中的约束 泛型概述 Bruce Eckel :您能对泛型做一个快速的介绍么? Anders Hejlsberg : 泛 ...
- hive如何使用中文查询条件
直接在hql中使用中文会报错:org.apache.hadoop.ipc.RemoteException: java.io.IOException: java.lang.RuntimeExceptio ...