C++ lambda

轉載:http://blog.csdn.net/xuexiacm/article/details/39835085

lambda表達式:

  1. [capture_block](parameters) mutable exception_specification->return_type{ body }  

lambda表達式包含以下部分:

捕捉塊(catpure block): 指定如何捕捉所在作用域中的變量,並供給lambda主體使用。

參數(parameter): (可選)lambda表達式使用的參數列表。只有在不使用任何參數,並且沒有自定mutable、一個exception_specification 和一個return_type的情況下可以忽略該列表,返回類型在某些情況下也是可以忽略的,詳見對return_type的說明:eg: [] {return 10;}

參數列表和普通函數的參數列表類似,區別如下:

參數不能有默認值。

不允許變長參數列表。

不允許未命名的參數。

mutable:(可選)如果所在作用域的變量是通過值捕捉到,那麼lambda表達式主體中可以使用這些變量的副本。這些副本默認標記爲const,因此lambda表達式的主體不能修改這些副本的值。如果lambda表達式標記爲mutable,那麼這些副本則不是const,因此主體可以修改這些本地副本。

exception_specification:(可選)用於指定lambda可以拋出的異常。

return_type:(可選)返回值的類型。如果忽略了return_type,那麼編譯器會根據以下原則判斷返回類型:

如果lambda表達式主體的形式爲{return expression;}那麼表達式return_type的類型爲expression的類型。

其他情況下的return_type爲void。

下面的例子演示瞭如何創建一個lambda表達式並立即執行這個表達式。這行代碼定義了一個沒有返回值也沒有任何參數的lambda表達式。

注意:尾部的(),這對括號使得這個lambda表達式立即執行:

  1. [] {cout << "Hello from Lambda" << endl; } ();  

  1. string result = [](const string & str) -> string { return "Hello from " + str; }("second Lambda");  
  2. cout << "Result: " << result << endl;  
輸出如下:
  1. Result: Hello from second Lambda  

根據前面的描述,這個例子中的返回值可以忽略:

  1. string result = [](const string & str){ return "Hello from " + str; }("second Lambda");  

還可以保存lambda表達式的指針,並且通過函數指針執行這個lambda表達式。使用C++11的auto關鍵字可以輕鬆地做到這一點:
  1. auto fn = [](const string& str) {return "hello from " + str; };  
  2. cout << fn("call 1") << endl;  
  3. cout << fn("call 2") << endl;  
輸出如下:
  1. Hello from call 1  
  2. Hello from call 2  


捕捉塊

lambda表達式的方括號部分稱爲lambda捕捉塊(capture block),在這裏可以指定如何從所在作用域中捕捉變量。捕捉變量的意思是可以在lambda表達式主體中使用這個變量。有兩種方式:

[=]:通過值捕捉所有變量

[&]:通過引用捕捉所有變量

指定空白的捕捉塊[]表示不從所在作用域中捕捉變量。還可以酌情決定捕捉那些變量以及這些變量的捕捉方法,方法是指定一個捕捉列表,其中帶有可選的默認捕捉選項。前綴爲&的變量通過引用捕捉。不帶前綴的變量通過值捕捉。默認捕捉應該是捕捉列表中的第一個元素,可以是=或&。

例如:

[&x]只通過引用捕捉x,不捕捉其他變量。

[x]只通過值捕捉x,不捕捉其他變量。

[=, &x, &y]默認通過值捕捉,變量x和y例外,這兩個變量通過引用捕捉。

[&, x]默認通過引用捕捉,變量x例外,這個變量通過引用捕捉。

[&x, &y]非法,因爲標誌符不允許重複。

通過引用捕捉變量的時候,一定保證黨lambda表達式在執行的時候,這個引用還是可用的。


將lambda表達式用作返回值

定義在<functional>頭文件中的std::function是多態的函數對象包裝,類似函數指針。它可以綁定至任何可以被調用的對象(仿函數、成員函數指針、函數指針和lambda表達式),只要參數和返回類型符合包裝的類型即可。返回一個double、接受兩個整數參數的函數包裝定義如下:

  1. function<double(intint)> myWrapper;  
通過使用std::function,可從函數中返回lambda表達式,看一下定義:
  1. function<int(void)> multiplyBy2Lambda(int x)  
  2. {  
  3.     return [=]()->int{return 2 * x; };  
  4. }  

在這個例子中,lambda表達式的返回類型和空參數列表可以忽略,可改寫爲:
  1. function<int(void)> multiplyBy2Lambda(int x)  
  2. {  
  3.     return[=] {return 2 * x; };  
  4. }  
這個函數的主體部分創建了一個lambda表達式,這個lambda表達式通過值捕捉所在作用域的變量,並返回一個整數,這個返回的整數是傳給multiplyBy2Lambda()的值的兩倍。這個multiplyBy2Lambda()函數的返回值類型爲 function<int(void)>,即一個不接受參數並返回一個整數的函數。函數主體中定義的lambda表達式正好匹配這個原型。變量x通過值捕捉,因此,在lambda表達式從函數返回之前,x值的一份副本綁定至lambda表達式中的x。

可以通過以下方式調用上述函數:

  1. function<int(void)> fn = mutiplyBy2Lambda(5);  
  2. cout << fn() << endl;  
通過C++11的auto關鍵字可以簡化這個調用:
  1. auto fn = mutiplyBy2Lambda(5);  
  2. cout << fn() << endl;  
輸出爲10。

mutiplyBy2Lambda()示例通過值捕捉了變量x:[=]。假設這個函數重寫爲通過引用捕捉變量:[&],如下所示。根據代碼所示。根據代碼後面的解釋,下面這段代碼不能正常工作:

  1. function<int(void)> mutiplyBy2Lambda(int x)  
  2. {  
  3.     return[&] {return 2 * x; };  
  4. }  

lambda表達式通過引用捕捉變量x。然而,lambda表達式會在程序後面執行,而不會在mutiplyBy2Lambda()函數的作用域中執行,在那裏x的引用不再有效。


將lambda表達式用作參數:
您可以編寫lambda表達式作爲參數的函數。例如,可通過這種方式實現回調函數。下面的代碼實現了一個testCallback()函數,這個函數接受一個整數vector和一個回調函數作爲參數。這個實現迭代給定vector中的所有元素,並對每個元素調用回調函數,回調函數接受vector中每個元素作爲int參數,並返回一個布爾值。如果回調函數返回false,那麼停止迭代。

  1. void testCallback(const vector<int>& vec, const function<bool(int)>& callback)  
  2. {  
  3.     for (auto i : vec)  
  4.     {  
  5.         if (!callback(i))  
  6.             break;  
  7.         cout << i << " ";  
  8.     }  
  9.     cout << endl;  
  10. }  
可以按照以下方式測試testCallback()函數。
  1. vector<int> vec(10);  
  2. int index = 0;  
  3. generate(vec.begin(), vec.end(), [&index] {return ++index; });  
  4. for each (vec.begin(), vec.end()m[](int i) {cout << u << " "; });  
  5. {  
  6.     cout << endl;  
  7.     testCallback(vec, [](int i){return i < 6; });  
  8. }  

輸出結果:

  1. 1 2 3 4 5 6 7 8 9 10  
  2. 1 2 3 4 5 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章