在学习到《Essential C++》3.6节时自己按照自己的想法来实现书上提到的思路。代码虽然简单,不过自己却发现有很多其他地方不熟悉,比如函数指针的用法,仿函数和函数适配器的使用。捣鼓了半天,总算懂了点眉目,简单总结下以备忘。

文档按照五部分分写,先依次简单地介绍find()与find_if()算法、函数指针用法、仿函数(functon object)和函数适配器(function adapters)。最后贴上自己实验的代码并简单分析。

一、
因为问题起于泛型搜索算法find_if(),所以先总结下有关find()和find_if()。 声明:
        InputIterator
        find (InputIterator beg, InputIterator end, const T& value)
        InputIterator
        find_if(InputIterator beg, InputIterator end, UnaryPredicate op)第一种形式返回在搜索域[beg,end)内与value值相等的元素的地址;
第二种形式返回在搜索域[beg,end)内满足一元谓词函数op(elem)为真的元素的地址。
     1) 以上两种形式在搜索不到匹配元素的情况下均返回end;
     2) 注意op函数调用期间不能够改变自身的状态;
     3) op不能更改传递进来的参数;

二、
为了增强泛型算法的灵活性,一些泛型算法允许传递用户自定的的函数。泛型算法在使用辅助函数时有不同的方式,有些是可以省略的,即算法是可以不用给定的函数,而有些是强制性的,即必须使用这些函数。如下         
// CODE SNIPPET
        void print (int elem)
        {         
                cout <<elem <<’ ‘;
        }
        ……
        for_each (coll.begin(), coll.end(), print);一种特殊的辅助函数便是谓词函数,谓词函数通常指的是返回值为boolean的函数,它们通常用来为排序或者搜索算法指定参照条件。在使用中谓词函数可分为带有一个参数的谓词函数(unary)和需要两个参数的谓词函数(binary),值得注意的是并不是所有返回值为boolean类型的函数都是合法的谓词函数。

三、
仿函数是一种对象,但它具有函数一样的功能,并且比函数更有优势。其中一点便是效率更高。我们使用的仿函数通常被声明为inline,所以其大部分执行逻辑在编译时已经基本确定,因而少掉了频繁调用函数的开销。可以自己定义简单的仿函数,如下: // CODE SNIPPET
class Print{
        public:
                void operator() (int elem) const
                {
                        cout <<elem <<’ ‘;
                 }
};
……
for_each (coll.begin(), coll.end(), Print());
……C++的STL中提供了多种预定义的仿函数,如negate<type>(), plus<type>(), minus<type>(), multiplies<type>(), divides<type>(), modulus<type>(), equal_to<type>(), not_equal_to<type>(), less<type>(), greater<type>(), less_equal<type>(), greater_equal<type>(), logical_not<type>(), logical_and<type>(), logical_or<type>().

四、
函数适配器也是一种仿函数,不过这种仿函数更为高等,因为它可以将一个仿函数与另一个仿函数/ 值/ 特殊的函数结合起来。

不难发现,STL常使用的仿函数虽然提供了多种有用的仿函数,然而这些仿函数均是通过迭代器对容器里面的元素进行操作,但是有时候你还需要用其他的值结合,这时候便可以使用函数适配器(见下面的例子)。

编译不能通过的代码如下所示: // code snippet
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>

using namespace std;

bool less_than(int a, int b)
{
        return (a<b ? true:false);
}

vector<int> filter(const vector<int> &vec, int filter_value, bool (*ptr_func)(int, int))
{
        vector<int> temp;
        vector<int>::const_iterator iter = vec.begin();

while (find_if(iter, vec.end(), ptr_func(*iter, filter_value)) != vec.end())
        {
                temp.push_back(*iter);
                ++iter;
        }        
        return temp;
}

void display(vector<int> &vec)
{
        for (int ix=0; ix<vec.size(); ++ix)
                cout <<vec[ix] <<" ";
        cout <<"\n";
}
        
int main()
{
        const int nsize = 5;
        int int_arr[nsize] = { 2, 4, 5, 6, 7};
        vector<int>vec(int_arr, int_arr+nsize);
        display(vec);
        vector<int>result;

result = filter(vec, 6, less_than);
        display(result);
        
        return 0;        
}可见,我在使用find_if()函数的时候,将里面本应该为“函数指针”的第三个参数写成了对这个函数的“函数调用”,这是不允许的。但整个程序的思路并没有错,因为上面的代码可以通过仿函数来解决的。

上面也提到,一般通用的仿函数仅是对容器里面的值进行处理,但本例的思路是需要将容器里面的每个值以此与另一个值val进行比较的。所以必须要使用到函数适配器来将一个仿函数与一个值进行绑定。如下是更正后的代码: // code snippet
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>

using namespace std;

bool less_than(int a, int b)
{
        return (a<b ? true:false);
}

vector<int> filter(const vector<int> &vec, int val, less<int>&lt)
{
        vector<int> nvec;
        vector<int>::const_iterator iter = vec.begin();
        
        while ((iter=find_if(iter, vec.end(), bind2nd(lt, val))) != vec.end())
        {
                nvec.push_back(*iter);
                iter ++;
        }
        return nvec;
}

void display(vector<int> &vec)
{
        for (int ix=0; ix<vec.size(); ++ix)
                cout <<vec[ix] <<" ";
        cout <<"\n";
}
        
int main()
{
        const int nsize = 5;
        int int_arr[nsize] = { 2, 4, 5, 6, 7};
        vector<int>vec(int_arr, int_arr+nsize);
        display(vec);
        vector<int>result;

result = filter(vec, 6, less<int>());
        display(result);
        
        return 0;

}

本文转自编程小翁博客园博客,原文链接:http://www.cnblogs.com/wengzilin/archive/2012/10/20/2732252.html,如需转载请自行联系原作者

find(),find_if(),以及巧妙的函数对象,函数适配器相关推荐

  1. 函数对象 函数嵌套 名称空间与作用域

    函数对象: 函数是第一类对象,即函数可以当做数据传递 1 可以被引用 2 可以当做参数传递 3 返回值可以是函数  (函数名 不带() 就是函数名的内存地址,带括号就是执行函数) 4 可以当做容器类型 ...

  2. ❥关于C++之函数指针函数对象

    函数指针 以下是<cstdlib>库中的一个排序数组的方法qsort()的函数原型. void qsort (void* base, size_t num, size_t size,int ...

  3. 闭关之 C++ 函数式编程笔记(一):函数式编程与函数对象

    目录 前言 第一章 函数式编程简介 1.1 命令式与声明式编程比较 1.2 纯函数(Pure functions) 1.2.1 避免可变状态 1.3 以函数方式思考问题 1.4 函数式编程的优点 1. ...

  4. 【C++】【第六篇-2】【黑马 p215~p242】【list容器】【set/multiset容器】【map/multimap容器】【函数对象】【谓词】【内建函数对象】

    [C++][第六篇-2][黑马 p215~p242][list容器][set/multiset容器][map/multimap容器][函数对象][谓词][内建函数对象] 3.7 list容器(p215 ...

  5. C++ 之 函数对象

    函数对象 概念: 重载函数调用操作符的类,其对象称为函数对象 函数对象使用重载的()时,行为类似函数调用,也叫仿函数 本质: 函数对象(仿函数)是一个类,不是一个函数 函数对象使用 函数对象在使用时, ...

  6. 【C++】什么是函数对象和函数对象的用处

    目录 什么是函数对象 函数对象的用处 什么是函数对象 class myprint {public:void operator()(int num){cout << "num &q ...

  7. python 返回函数对象_Python—函数对象与闭包

    一 函数对象 函数对象指的是函数可以被当做"数据"来处理,具体可以分为四个方面的使用. 1.1 函数可以被引用 def index(): print('from index') a ...

  8. STL算法中函数对象和谓词

    算法中函数对象和谓词 函数对象和谓词定义 函数对象 谓词 一元函数对象案例 一元谓词案例 二元函数对象案例 二元谓词案例 预定义函数对象和函数适配器 使用预定义函数对象 算术函数对象 关系函数对象 逻 ...

  9. python 函数可以作为容器对象的元素_python第十二天, 三元表达式, 函数对象,名称空间与作用域,函数的嵌套定义...

    复习 1. 字符串的比较: 2. 函数的参数:形参与实参 3. 实参的分类:位置实参与关键字实参 4. 形参分类: 1.无值位置形参 2.有值位置形参 3.可变长位置形参 4.有无值关键字形参 5.可 ...

  10. C++/C--lambda表达式与函数对象【转载】

    文章目录 1. 概念 2 lambda表达式 3 lambda新特性 3.1 lambda捕捉表达式 3.2 泛型lambda表达式 3.3 函数对象 4 函数适配器 5 绑定器(binder) 5 ...

最新文章

  1. 我是如何在SQLServer中处理每天四亿三千万记录的
  2. 关于align=absmiddle的说明
  3. iPhone 12 mini被质疑锁屏触摸不灵
  4. 20190810:存在重复(三种解法)
  5. java cache缓存_Redis缓存失效策略思考
  6. python如何制作一个工程软件_如何利用python制作一个解压缩软件-Go语言中文社区...
  7. 安装python多少内存_Python进程使用的全部内存?
  8. 计算机网络那些事~(二)
  9. 再说“两本交换机图书内容完全不一样”
  10. 圣思园java笔记_最详细JAVA高并发多线程VIP课程--圣思园--笔记
  11. 在DW中如何让代码对齐?
  12. html 网页表格居中,网页中表格如何居中
  13. 手机抓包软件:charles安装及教程
  14. esxi 快照整合_ESXi删除最后的快照
  15. PS从复制图层到的项目
  16. 002 - new javascript 基础
  17. Docker学习——DockerFile
  18. 回忆数学老前辈孙元远先生
  19. 基于MATLAB的Cplex、Yalmip环境安装
  20. excel 进行二叉树_基础扩展 | 20. 建立二叉树

热门文章

  1. 2019-4-21 - plan
  2. csdn android视频播放器开发
  3. 自主编写的新书出版2个月,竟然上了51cto读书频道的动态首页,兴奋中!
  4. Oauth协议是否会泄露用户的密码
  5. Linux shell命令提示符
  6. 系统视图和用户视图的区别_读书笔记——数据库系统概论
  7. 图片异步加载框架 Android-Universal-Image-Loader
  8. 助力南京打造创新名城 第三届未来网络发展大会将召开
  9. 数据分析Power BI数据可视化教程(二)——关于切片器和地图可视化教程
  10. 电商系统设计之商品 (下)