1、何为仿函数

仿函数的主要功能是为了搭配STL算法使用,单独使用仿函数的情况比较少。 
仿函数(functors)在C++标准中采用的名称是函数对象(function objects)。仿函数主要用于STL中的算法中,虽然函数指针虽然也可以作为算法的参数,但是函数指针不能满足STL对抽象性的要求,也不能满足软件积木的要求–函数指针无法和STL其他组件搭配,产生更灵活变化。仿函数本质就是类重载了一个operator(),创建一个行为类似函数的对象。

对于重载了()操作符的类,可以实现类似函数调用的过程,所以叫做仿函数,实际上仿函数对象仅仅占用1字节,因为内部没有数据成员,仅仅是一个重载的方法而已。实际上可以通过传递函数指针实现类似的功能,但是为了和STL内部配合使用,他提供了仿函数的特性。

struct MyPlus{int operator()(const int &a , const int &b) const{return a + b;}
};int main()
{MyPlus a;cout << MyPlus()(1,2) << endl;//1、通过产生临时对象调用重载运算符cout << a.operator()(1,2) << endl;//2、通过对象显示调用重载运算符cout << a(1,2) << endl;//3、通过对象类似函数调用 隐示地调用重载运算符return 0;
}

在STL中,当需要传递仿函数对象的时候,通过采用上述第1种方法,因为传递进去仅仅为了给容器内部成员赋值,所以没有必要生成对象,产生临时对象即可。

2、STL中基础仿函数

1、仿函数定义自己型别 

算法内部可能需要使用仿函数返回值或者输出值的类型参数,因此定义两个类。

//一元函数的参数和返回值类型,通常被继承

template <class Arg, class Result>
struct unary_function {typedef Arg argument_type;typedef Result result_type;
};

//二元函数的参数和返回值类型,通常被继承

template <class Arg1, class Arg2, class Result>
struct binary_function {typedef Arg1 first_argument_type;typedef Arg2 second_argument_type;typedef Result result_type;
};  

上述两个类分别定义了一元和二元函数参数和返回值型别,对应的仿函数类仅仅需要继承此类即可。

2、算术类仿函数 

标准库给我们定义了一些通用的仿函数,可以直接调用,生成对象,面向用户。//算术类仿函数 + - * / %
//plus仿函数,生成一个对象,里面仅仅有一个函数重载的方法。

template <class T>
struct plus : public binary_function<T, T, T> {T operator()(const T& x, const T& y) const { return x + y; }
};//minus仿函数
template <class T>
struct minus : public binary_function<T, T, T> {T operator()(const T& x, const T& y) const { return x - y; }
};template <class T>
struct multiplies : public binary_function<T, T, T> {T operator()(const T& x, const T& y) const { return x * y; }
};template <class T>
struct divides : public binary_function<T, T, T> {T operator()(const T& x, const T& y) const { return x / y; }
};
template <class T>
struct modulus : public binary_function<T, T, T> {T operator()(const T& x, const T& y) const { return x % y; }
};//取负值
template <class T>
struct negate : public unary_function<T, T> {T operator()(const T& x) const { return -x; }
};

单独使用仿函数,通常将仿函数和算法部分单独分开使用。

#include <iostream>     // std::cout
#include <functional>   // std::plus
#include <algorithm>    // std::transform
using namespace std;
int main(void)
{cout << minus<int>()(10,5) << endl;//5cout << multiplies<int>()(10,5) << endl;//50cout << divides<int>()(10,5) << endl;//2cout << modulus<int>()(10,5) << endl;//0cout << negate<int>()(10) << endl;//-10return 0;
}

3、关系运算符仿函数

//关系运算符仿函数
// x==y 仿函数

template <class T>
struct equal_to : public binary_function<T, T, bool> {bool operator()(const T& x, const T& y) const { return x == y; }
};// x!=y 仿函数
template <class T>
struct not_equal_to : public binary_function<T, T, bool> {bool operator()(const T& x, const T& y) const { return x != y; }
};
// x>y 仿函数
template <class T>
struct greater : public binary_function<T, T, bool> {bool operator()(const T& x, const T& y) const { return x > y; }
};
// x<y 仿函数
template <class T>
struct less : public binary_function<T, T, bool> {bool operator()(const T& x, const T& y) const { return x < y; }
};// x>=y 仿函数
template <class T>
struct greater_equal : public binary_function<T, T, bool> {bool operator()(const T& x, const T& y) const { return x >= y; }
};
// x<=y 仿函数
template <class T>
struct less_equal : public binary_function<T, T, bool> {bool operator()(const T& x, const T& y) const { return x <= y; }
};

// sort algorithm example

#include <iostream>     // std::cout
#include <algorithm>    // std::sort
#include <vector>       // std::vector
#include <functional>   // std::bool myfunction (int i,int j) { return (i < j); }int main () {int myints[] = {32,71,12,45,26,80,53,33};std::vector<int> myvector (myints, myints+8);               // 32 71 12 45 26 80 53 33// using default comparison (operator <):std::sort (myvector.begin(), myvector.begin()+4);           //(12 32 45 71)26 80 53 33// using function as compstd::sort (myvector.begin()+4, myvector.end(), myfunction); // 12 32 45 71(26 33 53 80)// using object as compstd::sort (myvector.begin(), myvector.end(), std::less<int>());     //(12 26 32 33 45 53 71 80)// print out content:std::cout << "myvector contains:";for (std::vector<int>::iterator it=myvector.begin(); it!=myvector.end(); ++it)std::cout << ' ' << *it;std::cout << '\n';return 0;
}

4、逻辑运算符仿函数

template <class T>
struct logical_and : public binary_function<T, T, bool> {bool operator()(const T& x, const T& y) const { return x && y; }
};template <class T>
struct logical_or : public binary_function<T, T, bool> {bool operator()(const T& x, const T& y) const { return x || y; }
};template <class T>
struct logical_not : public unary_function<T, bool> {bool operator()(const T& x) const { return !x; }
};

5、证同、选择、投射仿函数

///
//证同仿函数,主要用于RB或者hashmap里面 key = value情况

template <class T>
struct identity : public unary_function<T, T> {const T& operator()(const T& x) const { return x; }
};//选择仿函数,主要用与RB和hashmap里面key 不为value情况,从pair种取出key
template <class Pair>
struct select1st : public unary_function<Pair, typename Pair::first_type> {const typename Pair::first_type& operator()(const Pair& x) const{return x.first;}
};//选择仿函数,主要用与RB和hashmap里面key 不为value情况,从pair种取出value
template <class Pair>
struct select2nd : public unary_function<Pair, typename Pair::second_type> {const typename Pair::second_type& operator()(const Pair& x) const{return x.second;}
};//投射函数,输入x和y返回x
template <class Arg1, class Arg2>
struct project1st : public binary_function<Arg1, Arg2, Arg1> {Arg1 operator()(const Arg1& x, const Arg2&) const { return x; }
};
//投射函数,输入x和y返回y
template <class Arg1, class Arg2>
struct project2nd : public binary_function<Arg1, Arg2, Arg2> {Arg2 operator()(const Arg1&, const Arg2& y) const { return y; }
};

3、STL中仿函数适配器

仿函数适配器是通过将上述仿函数重新配置成含有新功能的模板函数。

1、对仿函数返回值进行否定适配器

传入仿函数对象即可,和以前一样使用,仅仅包装了一下子而已。

//否定一元返回值
//模板参数传入仿函数类

template <class Predicate>
class unary_negate: public unary_function<typename Predicate::argument_type, bool> {
protected:Predicate pred;//对象
public:explicit unary_negate(const Predicate& x) : pred(x) {}bool operator()(const typename Predicate::argument_type& x) const {return !pred(x);//这里是调用的关键}
};
//辅助函数,使得我们方便使用unary_negate<Pred>
//传入对象,并返回临时对象。
template <class Predicate>
inline unary_negate<Predicate> not1(const Predicate& pred) {return unary_negate<Predicate>(pred);//返回临时对象
}
//辅助函数,识别传入对象,通过模板萃取其模板型别,然后声明模板声明临时对象并用传入对象初始化。
/
//否定二元返回值
template <class Predicate>
class binary_negate : public binary_function<typename Predicate::first_argument_type,typename Predicate::second_argument_type,bool> {
protected:Predicate pred;
public:explicit binary_negate(const Predicate& x) : pred(x) {}bool operator()(const typename Predicate::first_argument_type& x, const typename Predicate::second_argument_type& y) const {return !pred(x, y); }
};
template <class Predicate>
inline binary_negate<Predicate> not2(const Predicate& pred) {return binary_negate<Predicate>(pred);
}

//not1 example

#include <iostream>     // std::cout
#include <functional>   // std::not1
#include <algorithm>    // std::count_ifstruct IsOdd {bool operator() (const int& x) const {return x%2 == 1;}typedef int argument_type;
};//类int main () {int values[] = {1,2,3,4,5};int cx = std::count_if( values, values+5, std::not1(IsOdd()) );//找出不是奇数的个数//IsOdd()产生临时对象a,not1返回临时对象并用a初始化。std::cout << "There are " << cx << " elements with even values.\n";return 0;
}

输出: 
There are 2 elements with even values.

// not2 example

#include <iostream>     // std::cout
#include <functional>   // std::not2, std::equal_to
#include <algorithm>    // std::mismatch
#include <utility>      // std::pairint main () {int foo[] = {10,20,30,40,50};int bar[] = {0,15,30,45,60};std::pair<int*,int*> firstmatch,firstmismatch;firstmismatch = std::mismatch (foo, foo+5, bar, std::equal_to<int>());//返回第一个不匹配数值firstmatch = std::mismatch (foo, foo+5, bar, std::not2(std::equal_to<int>()));//返回第一个匹配的数值std::cout << "First mismatch in bar is " << *firstmismatch.second << '\n';std::cout << "First match in bar is " << *firstmatch.second << '\n';return 0;
}

输出: 
First mismatch in bar is 0 
First match in bar is 30

2、将仿函数某个参数绑定为固定值的适配器

//绑定参数,将二元函数某个参数绑定为恒定值///
//

//Operation前面讲解的仿函数类
template <class Operation>
class binder2nd: public unary_function<typename Operation::first_argument_type,typename Operation::result_type> {
protected:Operation op;//仿函数对象typename Operation::second_argument_type value;//第二个参数类型
public:binder2nd(const Operation& x,const typename Operation::second_argument_type& y) : op(x), value(y) {}//传入x是对象的引用,第二参数的引用typename Operation::result_typeoperator()(const typename Operation::first_argument_type& x) const {//传入x,底层调用opreturn op(x, value);//将value绑定为op的第二个参数 }
};//辅助函数,辅助产生绑定好的对象 bind2nd
template <class Operation, class T>
inline binder2nd<Operation> bind2nd(const Operation& op, const T& x) {typedef typename Operation::second_argument_type arg2_type;return binder2nd<Operation>(op, arg2_type(x));//仅仅产生临时对象,可以传给模板函数
}//第一个参数绑定起来
template <class Operation>
class binder1st: public unary_function<typename Operation::second_argument_type,typename Operation::result_type> {
protected:Operation op;//操作typename Operation::first_argument_type value;//第一个参数类型
public:binder1st(const Operation& x,const typename Operation::first_argument_type& y): op(x), value(y) {}//构造typename Operation::result_typeoperator()(const typename Operation::second_argument_type& x) const {return op(value, x); }
};//辅助函数调用进行
template <class Operation, class T>
inline binder1st<Operation> bind1st(const Operation& op, const T& x) {typedef typename Operation::first_argument_type arg1_type;return binder1st<Operation>(op, arg1_type(x));
}

// binder2nd example

#include <iostream>
#include <functional>
#include <algorithm>
using namespace std;int main () {int numbers[] = {10,-20,-30,40,-50};int cx;int cx1;binder2nd< less<int> > IsNegative (less<int>(),0);//将less<int>重新包装产生新的对象binder2ndcx = count_if (numbers,numbers+5 , IsNegative);//二者用法一样cx1 = count_if (numbers,numbers+5,bind2nd(less<int>() , 0));cout << "There are " << cx <<"  "<< cx1 << " negative elements.\n";return 0;
}

3、将两个仿函数合并成一个仿函数的适配器

///用于函数合成/

//一元仿函数合成操作
//h(x) = f( g(x) )
template <class Operation1, class Operation2>
class unary_compose : public unary_function<typename Operation2::argument_type,typename Operation1::result_type> {
protected:Operation1 op1;Operation2 op2;
public:unary_compose(const Operation1& x, const Operation2& y) : op1(x), op2(y) {}typename Operation1::result_typeoperator()(const typename Operation2::argument_type& x) const {return op1(op2(x));//类似f(g(x))}
};template <class Operation1, class Operation2>
inline unary_compose<Operation1, Operation2> compose1(const Operation1& op1, const Operation2& op2) {return unary_compose<Operation1, Operation2>(op1, op2);//返回临时对象
}//二元仿函数合成操作
//h(x) = f( g1(x) , g2(x) )
template <class Operation1, class Operation2, class Operation3>
class binary_compose: public unary_function<typename Operation2::argument_type,typename Operation1::result_type> {
protected:Operation1 op1;Operation2 op2;Operation3 op3;
public:binary_compose(const Operation1& x, const Operation2& y, const Operation3& z) : op1(x), op2(y), op3(z) { }typename Operation1::result_typeoperator()(const typename Operation2::argument_type& x) const {return op1(op2(x), op3(x));//返回临时对象}
};template <class Operation1, class Operation2, class Operation3>
inline binary_compose<Operation1, Operation2, Operation3>
compose2(const Operation1& op1, const Operation2& op2, const Operation3& op3) {return binary_compose<Operation1, Operation2, Operation3>(op1, op2, op3);
}

4、将函数指针合并成仿函数的适配器

///用于函数指针/

//将一元函数指针包装成仿函数
template <class Arg, class Result>
class pointer_to_unary_function : public unary_function<Arg, Result> {
protected:Result (*ptr)(Arg);//函数指针变量
public:pointer_to_unary_function() {}explicit pointer_to_unary_function(Result (*x)(Arg)) : ptr(x) {}Result operator()(Arg x) const { return ptr(x); }
};template <class Arg, class Result>
inline pointer_to_unary_function<Arg, Result> ptr_fun(Result (*x)(Arg)) {return pointer_to_unary_function<Arg, Result>(x);//传入函数指针、一元参数类型、返回值类型,返回一个仿函数对象
}///将二元函数指针包装成仿函数
template <class Arg1, class Arg2, class Result>
class pointer_to_binary_function : public binary_function<Arg1, Arg2, Result> {
protected:Result (*ptr)(Arg1, Arg2);
public:pointer_to_binary_function() {}explicit pointer_to_binary_function(Result (*x)(Arg1, Arg2)) : ptr(x) {}Result operator()(Arg1 x, Arg2 y) const { return ptr(x, y); }
};template <class Arg1, class Arg2, class Result>
inline pointer_to_binary_function<Arg1, Arg2, Result>
ptr_fun(Result (*x)(Arg1, Arg2)) {return pointer_to_binary_function<Arg1, Arg2, Result>(x);//返回对象即可
}

// ptr_fun example

#include <iostream>
#include <functional>
#include <algorithm>
#include <cstdlib>
#include <numeric>
using namespace std;int main () {char* foo[] = {"10","20","30","40","50"};int bar[5];int sum;transform (foo, foo+5, bar, ptr_fun(atoi) );//将函数指针转换成仿函数对象,这里输入函数指针效果一样transform (foo, foo+5, bar, atoi );sum = accumulate (bar, bar+5, 0);cout << "sum = " << sum << endl;return 0;
}

输出: 
sum = 150

5、将成员函数指针提取出来包装成仿函数适配器

//函数指针类别:返回S 无输入  通过指针调用
template <class S, class T>
class mem_fun_t : public unary_function<T*, S> {
public:explicit mem_fun_t(S (T::*pf)()) : f(pf) {}//初始化S operator()(T* p) const { return (p->*f)(); }//调用,p里面对应的函数
private:S (T::*f)();//这是一个变量,这个函数指针变量
};
//辅助函数,直接通过模板萃取相应的型别,然后声明相应的对象
template <class S, class T>
inline mem_fun_t<S,T> mem_fun( S (T::*f)() ) { return mem_fun_t<S,T>(f);//返回仿函数临时对象,真的很牛逼哦抽象出来了
}
//小例子
size_type length() const
{ return _M_string_length; }
mem_fun(&string::length);//传入函数指针,::优先级大于&
//s 是 size_type  T是string  f是length,通过模板萃取出这些型别,即可产生相应的对象。//有一个参数,通过指针调用
template <class S, class T, class A>
class mem_fun1_t : public binary_function<T*, A, S> {
public:explicit mem_fun1_t(S (T::*pf)(A)) : f(pf) {}S operator()(T* p, A x) const { return (p->*f)(x); }
private:S (T::*f)(A);
};template <class S, class T, class A>
class const_mem_fun1_t : public binary_function<const T*, A, S> {
public:explicit const_mem_fun1_t(S (T::*pf)(A) const) : f(pf) {}S operator()(const T* p, A x) const { return (p->*f)(x); }
private:S (T::*f)(A) const;
};

// mem_fun example

#include <iostream>
#include <functional>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;int main () {vector <string*> numbers;// populate vector of pointers:numbers.push_back ( new string ("one") );numbers.push_back ( new string ("two") );numbers.push_back ( new string ("three") );numbers.push_back ( new string ("four") );numbers.push_back ( new string ("five") );vector<int> lengths(numbers.size());//预先分配内存空间transform (numbers.begin(), numbers.end(), lengths.begin(), mem_fun(&string::length));for (int i=0; i<5; i++) {cout << *numbers[i] << " has " << lengths[i] << " letters.\n";}// deallocate strings:for (vector<string*>::iterator it = numbers.begin(); it!=numbers.end(); ++it)delete *it;return 0;
}

输出: 
one has 3 letters. 
two has 3 letters. 
three has 5 letters. 
four has 4 letters. 
five has 4 letters.

STL之仿函数实现详解相关推荐

  1. STL 之 deque容器详解

    Deque 容器 deque容器是C++标准模版库(STL,Standard Template Library)中的部分内容.deque容器类与vector类似,支持随机访问和快速插入删除,它在容器中 ...

  2. STL 之 list 容器详解

    STL之list容器详解 List 容器 list是C++标准模版库(STL,Standard Template Library)中的部分内容.实际上,list容器就是一个双向链表,可以高效地进行插入 ...

  3. C++ STL容器 —— array 用法详解

    C++ STL容器 -- array 用法详解 写在前面:近期正在学习C++的STL容器,因此在这里做一下日志记录,主要介绍一些容器基本成员函数的用法, 配上实际用例,并不涉及原理.但别人的博客终究是 ...

  4. STL —— multimap的用法详解

    文章目录 multimap的基本性质 STL--multimap容器的用法 multimap容器的创建与初始化 multimap容器包含的成员方法 multimap容器大小 multimap容器中键值 ...

  5. STL中map用法详解

    Map是STL的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据处理能力,由于这个特性,它完成有可能在我们处理一对一数据的时候 ...

  6. [转] STL中map用法详解

    一.Map概述          Map是STL的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据处理能力,由于这个特性,它完 ...

  7. STL中的list详解

    STL中的list就是一双向链表,可高效地进行插入删除元素. list不支持随机访问.所以没有 at(pos)和operator[]. list对象list1, list2分别有元素list1(1,2 ...

  8. C++:迭代器(STL迭代器)iterator详解

    STL迭代器 参考链接:http://c.biancheng.net/view/338.html

  9. STL中list用法详解

    本文转载自百度文库.作者如下.其中下面的count, count_if等函数的使用有些陈旧,如在编译时遇到问题,请百度. 标准模板库(STL)介绍 作者:Scott Field 本文以List容器为例 ...

  10. 【STL深入学习】SGI STL空间配置器详解(二)-第二级空间配置器

    本文讲解SGI STL空间配置器的第二级配置器. 相比第一级配置器,第二级配置器多了一些机制,避免小额区块造成内存的碎片.不仅仅是碎片的问题,配置时的额外负担也是一个大问题.因为区块越小,额外负担所占 ...

最新文章

  1. 用thttpd做Web Server
  2. MYSQL、SQL在LIKE里传的参数没有赋进去的原因
  3. 3.1_栈_顺序存储结构(数组形式)
  4. Quartz-Trigger详解
  5. axios不发起请求_axios 发 post 请求的问题
  6. 「 每日一练,快乐水题 」191. 位1的个数
  7. 关于aop:pointcut的expression配制说明及JoinPoint
  8. 使用Spring Security对RESTful服务进行身份验证
  9. java比较时间sql_如何正确比较日期 java.sql.Date
  10. Linux命令之crontab命令
  11. 编程实现 带符号加法溢出判断
  12. APT 分析报告:钓鱼邮件网址如何混淆 URL 逃避检测?
  13. 算法学习(四)冒泡排序
  14. 搭建自己的IOT平台——EMQ
  15. Energy python API 代码学习
  16. STM32F407VET6+cubemx+FSMC+ST7789
  17. 如何免费自动将邮件发送到多个邮件地址 - 自动邮件发送器使用教程
  18. 微信自定义菜单java_java微信开发API第四步 微信自定义个性化菜单实现
  19. PHP程序员战地日记
  20. 华为2018优招 解决方案技术工程师

热门文章

  1. html 5拜年贺卡,HTML5+CSS3实现春节贺卡
  2. oracle 进入empt,关于redhat6.2静默安装oracle11g出现的问题 大神救命
  3. 家谱管理系统性能要求_应用在Mac上的家谱族谱工具
  4. mysql 核对_mysql索引 (校验规则引发的血案)
  5. jsp开发项目中的问题解决
  6. win10右键卡顿原因_个个都能惊呆你WIN10小技巧分享(无需安装第三方软件)
  7. micropython thread_功能更新!C 函数也能在 MicroPython 中被调用啦
  8. python函数的传参要求_python函数传参问题,一直没弄明白
  9. javascript html coffee 编辑器,CoffeeCup HTML Editor (html编辑器)
  10. 8代cpu能装linux 系统吗,Intel支持八九代酷睿的B365芯片组将登场亮相