C++11新特性之八——函数对象function

http://www.cnblogs.com/yyxt/p/3987717.html

详细请看《C++ Primer plus》(第六版中文版)

http://www.cnblogs.com/lvpengms/archive/2011/02/21/1960078.html

备注:

函数对象
尽管函数指针被广泛用于实现函数回调,但C++还提供了一个重要的实现回调函数的方法,那就是函数对象。函数对象(也称“函数符”)是重载了“()”操作符的普通类对象。因此从语法上讲,函数对象与普通的函数行为类似。
用函数对象代替函数指针有几个优点:

  首先,因为对象可以在内部修改而不用改动外部接口,因此设计更灵活,更富有弹性。函数对象也具备有存储先前调用结果的数据成员。在使用普通函数时需要将先前调用的结果存储在全程或者本地静态变量中,但是全程或者本地静态变量有某些我们不愿意看到的缺陷。

  其次,在函数对象中编译器能实现内联调用,从而更进一步增强了性能。这在函数指针中几乎是不可能实现的。

  C++11还提供了limbda表达式来实现函数的灵活调用。详见《C++ Primer Plus》第18章。

----------------------------------------------------------------------------------------------------------------------------------------------------------

【以下转自】http://www.cnblogs.com/hujian/archive/2012/12/07/2807605.html

function是一组函数对象包装类的模板,实现了一个泛型的回调机制。function与函数指针比较相似,优点在于它允许用户在目标的实现上拥有更大的弹性,即目标既可以是普通函数,也可以是函数对象和类的成员函数,而且可以给函数添加状态。
声明一个function时,需要给出所包装的函数对象的返回值类型和各个参数的类型。比如,声明一个function,它返回一个bool类型并接受一个int类型和一个float类型的参数,可以像下面这样:
function<bool (int, float)> f;

下面简要介绍一下function的比较重要的几个接口。

function();
缺省构造函数,创建一个空的函数对象。如果一个空的function被调用,将会抛出一个类型为bad_function_call的异常。
template <typename F> function(F g);

这个泛型的构造函数接受一个兼容的函数对象,即这样一个函数或函数对象,它的返回类型与被构造的function的返回类型或者一样,或者可以隐式转换,并且它的参数也要与被构造的function的参数类型或者一样,或者可以隐式转换。注意,也可以使用另外一个function实例来进行构造。这样做,并且function g为空,则被构造的function也为空。使用空的函数指针和空的成员函数指针也会产生空的function。如果这样做,并且function g为空,则被构造的function也为空。使用空的函数指针和空的成员函数指针也会产生空的function。

template <typename F> function(reference_wrapper<F> g);
这个构造函数与前一个类似,但它接受的函数对象包装在一个reference_wrapper中,用以避免通过值来传递而产生函数或函数对象的一份拷贝。这同样要求函数对象兼容于function的签名。
function& operator=(const function& g);
赋值操作符保存g中的函数或函数对象的一份拷贝;如果g为空,被赋值的函数也将为空。
template<typename F> function& operator=(F g);
这个泛型赋值操作符接受一个兼容的函数指针或函数对象。注意,也可以用另一个 function 实例(带有不同但兼容的签名)来赋值。这同样意味着,如果g是另一个function实例且为空,则赋值后的函数也为空。赋值一个空的函数指针或空的成员函数指针也会使function为空。
bool empty() const;
这个成员函数返回一个布尔值,表示该function是否含有一个函数或函数对象。如果有一个目标函数或函数对象可被调用,它返回 false 。因为一个function可以在一个布尔上下文中测试,或者与0进行比较,因此这个成员函数可能会在未来版本的库中被取消,你应该避免使用它。
void clear();
这个成员函数清除 function, 即它不再关联到一个函数或函数对象。如果function已经是空的,这个调用没有影响。在调用后,function肯定为空。令一个function为空的首选方法是赋0给它;clear 可能在未来版本的库中被取消。
result_type operator()(Arg1 a1, Arg2 a2, ..., ArgN aN) const;
调用操作符是调用function的方法。你不能调用一个空的 function ,那样会抛出一个bad_function_call的异常。调用操作符的执行会调用function中的函数或函数对象,并返回它的结果。
下面分别给出使用function来包装普通函数,函数对象和类的成员函数的参考代码。
1、普通函数
复制代码
1 int Add(int x, int y)
2 
3 {
4             return x+y;
5 }
6 function<int (int,int)> f = Add;
7 int z = f(2, 3);
复制代码

2、函数对象

复制代码
 1 class CStudent2 {3 public:4             void operator() (string strName, int nAge)5             {6                 cout << strName << " : " << nAge << endl; 7             }8 };9 
10 CStudent stu;
11 function<void (string, int)> f = stu;
12 f("Mike",  12);
复制代码

3、类的成员函数

复制代码
 1 struct TAdd2 {3     int Add(int x,int y)4     {5         return x+y;6     }7 };8 9 function<int  (TAdd *, int, int)> f = TAdd::Add;
10 TAdd tAdd;
11 f(&tAdd, 2, 3);   // 如果前面的模板参数为传值或引用,直接传入tAdd即可
复制代码

接下来我们来看看使用function来保存函数对象状态的情况。考虑下面的代码:

复制代码
 1 class CAdd2 {3 public:4     CAdd():m_nSum(0) { NULL; }5     int operator()(int i)  //重载 () 运算符6     {7           m_nSum += i;8           return m_nSum;9     }
10 
11     int Sum() const 
12     {
13         return m_nSum;
14     }
15 
16 private:
17     int m_nSum;
18 };
19 
20 int main() 
21 {
22     CAdd add;
23     function<int (int)> f1 = add;
24     function<int (int)> f2 = add;
25     cout << f1(10) << "," << f2(10) << "," << add.Sum() << endl;
26     return 0;
27 }
复制代码
可能和大家想象的结果不一样,上面程序的输出是:10,10,0。我们将同一个函数对象赋值给了两个function,然后分别调用了这两个function,但函数对象中m_nSum的状态并没有被保持,问题出在哪儿呢?这是因为function的缺省行为是拷贝一份传递给它的函数对象,于是f1和f2中保存的都是add对象的拷贝,调用f1和f2后,add对象中的值并没有被修改。

C++ 11中提供了ref和cref函数,来提供对象的引用和常引用的包装。要使function能够正确地保存函数对象的状态,我们可以这样来修改代码:

1 CAdd add;
2 function<int(int)> f1 = ref(add);
3 function<int(int)> f2 = ref(add);
另外,在两个function之间赋值时,如果源function保存的是函数对象的拷贝,则目标function保存的也是函数对象的拷贝;如果源function保存的是函数对象的引用,则目标function保存的也是函数对象的引用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/384215.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

分块思想

今天学习了一个算法&#xff08;这个应该叫做算法吧&#xff1f;&#xff09;叫做分块&#xff08;和莫队&#xff0c;但是莫队还没有搞懂&#xff0c;搞懂再来写吧&#xff09; 听起来很高级&#xff0c;蒟蒻表示瑟瑟发抖。但是学完发现怎么那么像是一种变相的暴力呢。 分块思…

从零开始学C++之STL(八):函数对象、 函数对象与容器、函数对象与算法

http://blog.csdn.net/jnu_simba/article/details/9500219 一、函数对象 1、函数对象&#xff08;function object&#xff09;也称为仿函数&#xff08;functor&#xff09; 2、一个行为类似函数的对象&#xff0c;它可以没有参数&#xff0c;也可以带有若干参数。 3、任何重载…

树状数组初步理解

学习树状数组已经两周了&#xff0c;之前偷懒一直没有写&#xff0c;赶紧补上防止自己忘记&#xff08;虽然好像已经忘得差不多了&#xff09;。 作为一种经常处理区间问题的数据结构&#xff0c;它和线段树、分块一样&#xff0c;核心就是将区间分成许多个小区间然后通过对大区…

命名函数

函数体是代码块 代码块do...end是一种表达式的组织方式。 # ./times.exs下defmodule Times dodef doule(n) don * 2end end 函数调用与模式匹配 代码如下&#xff1a; # ./factorial.exs    计算阶层 defmodule Factorial dodef of(0), do: 1          #终止条件…

STL运用的C++技术(6)——函数对象

http://blog.csdn.net/wuzhekai1985/article/details/6658940?_t_t_t0.20427969420870595 STL是C标准库的重要组成部分之一&#xff0c;它不仅是一个可复用的组件库&#xff0c;更是一个包含算法与数据结构的软件框架&#xff0c;同时也是C泛型编程的很好例子。STL中运用了许多…

列表与递归

头部和尾部 [head | tail ] [1] #head 1 tail [] [head | tail ] [1, 2, 3] #head 1 tail [2, 3] [head | tail ] [] #报错 创建映射函数 我们可以使用一个函数来处理列表中的各个元素&#xff0c;如此可以接受更加复杂的处理&#xff0c;也可以…

优先队列小结

不像栈和队列&#xff0c;虽然STL有较好实现但是我们自己也可以很方便的实现&#xff0c;优先队列自己实现起来就比较复杂&#xff0c;比较浪费时间&#xff08;而且自己目前也不会233&#xff09;而优先队列因为其较好的特性经常被使用&#xff0c;因此对它的熟练掌握是做题的…

字典:散列表、散列字典、关键字列表、集合与结构体

字典 散列表和散列字典都实现了Dict的行为。Keyword模块也基本实现了&#xff0c;不同之处在于它支持重复键。 Eunm.into可以将一种类型的收集映射转化成另一种。 defmodule Sum dodef values(dict) dodict |> Dict.values |> Enum.sumend endhd [ one: 1, two: 2, thre…

C++11 学习笔记 lambda表达式

http://blog.csdn.net/fjzpdkf/article/details/50249287 lambda表达式是C11最重要也最常用的一个特性之一。lambda来源于函数式编程的概念&#xff0c;也是现代编程语言的一个特点。 一.函数式编程简介 定义&#xff1a;简单说&#xff0c;“函数式编程”是一种“编程范式”。…

Cutting Codeforces Round #493 (Div. 2)

Cutting There are a lot of things which could be cut — trees, paper, “the rope”. In this problem you are going to cut a sequence of integers. There is a sequence of integers, which contains the equal number of even and odd numbers. Given a limited bud…

Enum、Stream

Enum 其常见用法见&#xff1a;https://cloud.tencent.com/developer/section/1116852 在sort时&#xff0c;如果要获得稳定的排序结果&#xff0c;要使用< 而不是 <。 Stream Stream是延迟处理的&#xff0c;而Enum是贪婪的&#xff0c;则意味着传给它一个收集&#xff…

linux网络编程之posix 线程(三):posix 匿名信号量与互斥锁 示例生产者--消费者问题

http://blog.csdn.net/jnu_simba/article/details/9123603 一、posix 信号量 信号量的概念参见这里。前面也讲过system v 信号量&#xff0c;现在来说说posix 信号量。 system v 信号量只能用于进程间同步&#xff0c;而posix 信号量除了可以进程间同步&#xff0c;还可以线程间…

洛谷P1080-国王游戏-贪心+高精度

P1080-国王游戏 啊啊啊&#xff0c;刚才已经写了一次了&#xff0c;但是Edge浏览器不知道为什么卡住了&#xff0c;难受。 好吧&#xff0c;其实是一道可做题&#xff0c;分析得到的贪心策略就是就是将a * b小的放在前面&#xff08;其他的懒得说了&#xff09;&#xff0c;主要…

字符串与二进制

单引号字符串会被表示成整数值列表。 &#xff1f;c返回字符 c 的整数编码。下面这个例子用于解析字符列表表示法&#xff0c;该表示法用于表示一个任意的有符号的十进制数据。 defmodule Parse dodef number([ ?- | tail ]) do_number_digits(tail, 0) * -1enddef number([ ?…

P1092虫食算-深度优先搜索+玄学剪枝

P1092虫食算 这道题的思想并不复杂&#xff0c;可是难点在于各种玄学剪枝。在仔细研究了题解大佬的剪枝原理后终于氵了过去。 先上代码&#xff1a; #include<cstdio> #include<cstring> #include<algorithm> using namespace std;const int MAXN100; int n…

多进程

使用spawn创建一个新进程&#xff0c;其第一个参数是模块名、第二个参数是函数名、第三个参数是参数列表。spawn会返回一个进程标识符&#xff0c;通常叫做PID。 defmodule Spawn1 dodef greet doreceive do{sender, msg} ->send sender, { :ok, "Hello #{msg}" }…

Linux socket编程(二) 服务器与客户端的通信

http://www.cnblogs.com/-Lei/archive/2012/09/04/2670964.html上一篇写了对套接字操作的封装&#xff0c;这一节使用已封装好的Socket类实现服务器与客户端的通信&#xff08;Socket的定义见上篇Socket.h) 服务器端&#xff1a; ServerSocket.h #ifndef SERVERSOCKET_H #defin…

OTP服务器

defmodule Sequence.Server douse GenServerdef handle_call( :next_number, _from, current_number) do{ :reply, current_number, current_number 1}  #reply告诉OTP将第二个元素返回给客户端end end use的效果将OTP GenServer的行为添加到当前模块。这样它就可以处理所有…

洛谷P1040-加分二叉树-dp+二叉树

P1040-加分二叉树 这道题放在深度优先搜索的训练题中&#xff0c;可是我实在没有看出来应该怎么搜索。看了题解以后才看出来是一个很简单的dp(我果然还是太菜了) 看出dp并且算出来最大的分数不是很复杂&#xff0c;关键是输出给定中序遍历序列的二叉树的先序遍历&#xff0c;要…

UNIX网络编程:I/O复用技术(select、poll、epoll)

http://blog.csdn.net/dandelion_gong/article/details/51673085 Unix下可用的I/O模型一共有五种&#xff1a;阻塞I/O 、非阻塞I/O 、I/O复用 、信号驱动I/O 、异步I/O。此处我们主要介绍第三种I/O符复用。 I/O复用的功能&#xff1a;如果一个或多个I/O条件满足&#xff08;输…