仿函数(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)的更多相关文章

  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. 【uva 10294】 Arif in Dhaka (First Love Part 2) (置换,burnside引理|polya定理)

    题目来源:UVa 10294 Arif in Dhaka (First Love Part 2) 题意:n颗珠子t种颜色 求有多少种项链和手镯 项链不可以翻转 手镯可以翻转 [分析] 要开始学置换了. ...

  2. Hive 默认分区

    在hive里面表可以创建成分区表,但是当分区字段的值是'' 或者 null时 hive会自动将分区命名为默认分区名称. 默认情况下,默认分区的名称为__HIVE_DEFAULT_PARTITION__ ...

  3. luogu P1016 旅行家的预算

    题目描述 一个旅行家想驾驶汽车以最少的费用从一个城市到另一个城市(假设出发时油箱是空的).给定两个城市之间的距离D1.汽车油箱的容量C(以升为单位).每升汽油能行驶的距离D2.出发点每升汽油价格P和沿 ...

  4. JZYZOJ1502 [haoi2008]下落的圆盘 计算几何 贪心

    http://172.20.6.3/Problem_Show.asp?id=1502这种题用了快一天才写出来也是真的辣鸡.主要思路就是计算一下被挡住的弧度然后对弧度进行贪心.最开始比较困扰的是求弧度值 ...

  5. poj 1127(直线相交+并查集)

    Jack Straws Description In the game of Jack Straws, a number of plastic or wooden "straws" ...

  6. [COCI2011-2012#7] KAMPANJA

    这个题似曾相识啊,以前是用搜索剪枝+0/1边权bfs做的(题面可以参照上一篇这个题的博客). 有一类问题就是求 包含若干关键点的最小强联通子图大小是多少. 如果关键点数量是变量,那么就是NP问题了.. ...

  7. Error attempting to get column 'xxx' from result set. Cause: java.sql.SQLException: 无法转换为内部表示

    因为<resultMap>中映射的实体类属性类型与数据库字段类型不一致造成的.

  8. 活动中使用提示框(Toast)

    任务名称:活动中使用Toast 任务现象:点击button时,会弹出提示框:You Click Button 步骤 1.创建一个项目,新建活动和加载布局.参考: http://8c925c9a.wiz ...

  9. [转][Navicat for MySQL系列]Navicat如何使用(二)

    上一篇经验已经建立了数据连接,这篇我介绍一下Navicat for MySQL的“增删改查”功能是如何操作的. 工具/原料 Navicat for MySQL 10.1.7 数据库操作(基本) 1 远 ...

  10. leetcode 576. Out of Boundary Paths

    leetcode 576 题意大概就是在一个m*n的网格中,在坐标为[i,j]的网格上放一个物体,在规定时间N(t<=N)中,有多少种方法把物体移动出去.物体只能上下左右移动,一次移动一格,移动 ...