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.pswp.cn/news/384215.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/384215.shtml
英文地址,請注明出處:http://en.pswp.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;輸…