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, ...
随机推荐
- qwb与学姐 (带秩并查集)
qwb与学姐 Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 149 Solved: 54[Submit][Status][Web Board] Des ...
- CSS排版常用值指南
高对比度是确保网页阅读无障碍的关键,但也往往会被过分强调. 白底黑子会让打断文本显得过分密集,反而影响可读性. 文字颜色 3b4348 链接颜色 235ea7 衬线字体 font-family: &q ...
- Xamarin.Forms教程下载安装JDK配置环境变量
Xamarin.Forms教程下载安装JDK配置环境变量 Xamarin.Form环境配置下载安装JDK JDK是编程Java程序必须的软件.也许有人会问我们用的C#为什么还有Java呢?这是因为我们 ...
- 背包问题(dp基础)
题目描述: 在N件物品取出若干件放在容量为W的背包里,每件物品的体积为W1,W2……Wn(Wi为整数),与之相对应的价值为P1,P2……Pn(Pi为整数).求背包能够容纳的最大价值. Input 第1 ...
- request (请求对象)
一.学习请求 学习如何获取请求行, 请求头,请求体. 1. 获取请求行 获取请求方法 String method = request.getMethod(); System.out.println(m ...
- 【动态规划】【斜率优化】CDOJ1689 分序列
斜率优化裸题,模型可以看http://www.cnblogs.com/ka200812/archive/2012/08/03/2621345.html #include<cstdio> # ...
- 使用redis时出现java.util.ArrayList cannot be cast to java.lang.Long
java.lang.ClassCastException: java.util.ArrayList cannot be cast to java.lang.Long at redis.clients. ...
- Problem C: 程序改错(递归函数):数字转字符
Description 下面程序中“/ ***** N ***** /”的下一行中有错误,请改正(注意:不得加行.减行.加句.减句,否则后果自负). 该程序功能:用递归法将一个六位整数n转换成字符串, ...
- 利用Visual Studio Natvis 框架简化C++的变量调试工作
相信用C++开发过UI界面的程序员都对其变量调试工作头痛不已,由于复杂的继承关系,要查看到某个变量往往需要一系列的层层深入的点击,如下图就是查看TextBox的Text的例子: 为了查看Text属性, ...
- error C2248: 'MyString::pCharArray' : cannot access private member declared in class 'MyString'
std::ostream & operator<<(std::ostream os,const MyString & mystr){os<<mystr.pCha ...