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, ...
随机推荐
- 【分块】【bitset】hdu6085 Rikka with Candies
给你数组A和B,A B中的元素大小都不超过5w,且两两不同. q次询问,每次给你个k,问你有多少对(i,j),满足A(i)%B(j)==k. 如题目所言模拟bitset的过程,实质上是个分块,每块的大 ...
- SourceTree运行慢的解决方案
以下两个Git命令可以解决SourceTree运行慢: git gc git prune 可以在SourceTree点击命令行模式打开Git命令行窗口输入,等待片刻执行完成,SourceTree的运行 ...
- ES6 标签模板
标签模板其实不是模板,而是函数调用的一种特殊形式."标签"指的是函数,紧跟在后面的模板字符串就是它的参数. var a = 5; var b = 10; tag `Hello ${ ...
- Scala 匿名函数
Scala 中定义匿名函数的语法很简单,箭头左边是参数列表,右边是函数体. 使用匿名函数后,我们的代码变得更简洁了. 下面的表达式就定义了一个接受一个Int类型输入参数的匿名函数: var inc = ...
- linux shell实现随机数多种方法(date,random,uuid)
参考: http://www.cnblogs.com/chengmo/archive/2010/10/23/1858879.html $ cat /proc/sys/kernel/random/uui ...
- Linux中KVM虚拟机是什么
概念: Kernel-based Virtual Machine的简称,是一个开源的系统虚拟化模块,自Linux 2.6.20之后集成在Linux的各个主要发行版本中.它使用Linux自身的调度器进行 ...
- 从connect到express02-中间件morgan
控制台输出请求日志 输出格式 默认格式: dev, combined, tiny等 自定义格式: morgan(':method :url :status :res[content-length] - ...
- 转载:ArcEngine二次开发界面基本设置
转自:https://blog.csdn.net/weixin_42032107/article/details/80644991 1. 在form窗体中添加菜单栏和状态栏控件 2. 添加li ...
- 《ArcGIS Runtime SDK for Android开发笔记》——(5)、基于Android Studio构建ArcGIS Android开发环境(离线部署)(转)
1.前言 在上一篇的内容里我们介绍了基于Android Studio构建ArcGIS Runtime SDK for Android开发环境的基本流程,流程中我们采用的是基于Gradle的构建方式,在 ...
- win7怎么设置1440*900分辨率
右击桌面打开nvidia显卡控制面板显示一栏里面选择更改分辨率如果里面没有你要求的1440*900, 点下面的那个自定义,创建自定义分辨率,水平像素填1440,垂直扫描线填900. 创建完就可以应用了