1. 程式人生 > >C++11新特性:Lambda函式(匿名函式)

C++11新特性:Lambda函式(匿名函式)

基本的Lambda函式

我們可以這樣定義一個Lambda函式:

#include <iostream>  

using namespace std;  

int main()  
{  
    auto func = [] () { cout << "Hello world"; };  
    func(); // now call the function  
}  

其中func就是一個lambda函式。我們使用auto來自動獲取func的型別,這個非常重要。定義好lambda函式之後,就可以當這場函式來使用了。
其中 [ ] 表示接下來開始定義lambda函式,中括號中間有可能還會填引數,這在後面介紹。之後的()填寫的是lambda函式的引數列表{}中間就是函式體了。
正常情況下,只要函式體中所有return都是同一個型別的話,編譯器就會自行判斷函式的返回型別。也可以顯示地指定lambda函式的返回型別。這個需要用到函式返回值後置的功能,比如這個例子:

[] () -> int { return 1; }  

所以總的來說lambda函式的形式就是:

[captures] (params) -> ret {Statments;}  

Lambda函式的用處

假設你設計了一個地址簿的類。現在你要提供函式查詢這個地址簿,可能根據姓名查詢,可能根據地址查詢,還有可能兩者結合。要是你為這些情況都寫個函式,那麼你一定就跪了。所以你應該提供一個介面,能方便地讓使用者自定義自己的查詢方式。在這裡可以使用lambda函式來實現這個功能。

#include <string>  
#include <vector>  
class AddressBook { public: // using a template allows us to ignore the differences between functors, function pointers // and lambda template<typename Func> std::vector<std::string> findMatchingAddresses (Func func) { std::vector<std::string
>
results; for ( auto itr = _addresses.begin(), end = _addresses.end(); itr != end; ++itr ) { // call the function passed into findMatchingAddresses and see if it matches if ( func( *itr ) ) { results.push_back( *itr ); } } return results; } private: std::vector<std::string> _addresses; };

從上面程式碼可以看到,findMatchingAddressses函式提供的引數是Func型別,這是一個泛型型別。在使用過程中應該傳入一個函式,然後分別對地址簿中每一個entry執行這個函式,如果返回值為真那麼表明這個entry符合使用者的篩選要求,那麼就應該放入結果當中。那麼這個Func型別的引數如何傳入呢?

AddressBook global_address_book;  

vector<string> findAddressesFromOrgs ()  
{  
    return global_address_book.findMatchingAddresses(   
        // we're declaring a lambda here; the [] signals the start  
        [] (const string& addr) { return addr.find( ".org" ) != string::npos; }   
    );  
}  

可以看到,我們在呼叫函式的時候直接定義了一個lambda函式。引數型別是
const string& addr
返回值是bool型別。
如果使用者要使用不同的方式查詢的話,只要定義不同的lambda函式就可以了。

Lambda函式中的變數擷取

在上述例子中,lambda函式使用的都是函式體的引數和它內部的資訊,並沒有使用外部資訊。我們設想這樣的一個場景,我們從鍵盤讀入一個名字,然後用lambda函式定義一個匿名函式,在地址簿中查詢有沒有相同名字的人。那麼這個lambda函式勢必就要能使用外部block中的變數,所以我們就得使用變數擷取功能(Variable Capture)。

// read in the name from a user, which we want to search  
string name;  
cin>> name;  
return global_address_book.findMatchingAddresses(   
    // notice that the lambda function uses the the variable 'name'  
    [&] (const string& addr) { return name.find( addr ) != string::npos; }   
);  

從上述程式碼看出,我們的lambda函式已經能使用外部作用域中的變數name了。這個lambda函式一個最大的區別是[]中間加入了&符號。這就告訴了編譯器,要進行變數擷取。這樣lambda函式體就可以使用外部變數。如果不加入任何符號,編譯器就不會進行變數擷取。

下面是各種變數擷取的選項:
[] 不擷取任何變數
[&} 擷取外部作用域中所有變數,並作為引用在函式體中使用
[=] 擷取外部作用域中所有變數,並拷貝一份在函式體中使用
[=, &foo] 擷取外部作用域中所有變數,並拷貝一份在函式體中使用,但是對foo變數使用引用
[bar] 擷取bar變數並且拷貝一份在函式體重使用,同時不擷取其他變數
[this] 擷取當前類中的this指標。如果已經使用了&或者=就預設新增此選項。
Lambda函式和STL

lambda函式的引入為STL的使用提供了極大的方便。比如下面這個例子,當你想便利一個vector的時候,原來你得這麼寫:

vector<int> v;  
v.push_back( 1 );  
v.push_back( 2 );  
//...  
for ( auto itr = v.begin(), end = v.end(); itr != end; itr++ )  
{  
    cout << *itr;  
}  
現在有了lambda函式你就可以這麼寫
vector<int> v;  
v.push_back( 1 );  
v.push_back( 2 );  
//...  
for_each( v.begin(), v.end(), [] (int val)  
{  
    cout << val;  
} );  

相關推薦

C++11特性Lambda函式匿名函式

基本的Lambda函式 我們可以這樣定義一個Lambda函式: #include <iostream> using namespace std; int main() { auto func = [] () { c

C++11 特性Lambda 表示式

或許,Lambda 表示式算得上是 C++ 11 新增特性中最激動人心的一個。這個全新的特性聽起來很深奧,但卻是很多其他語言早已提供(比如 C#)或者即將提供(比如 Java)的。簡而言之,Lambda 表示式就是用於建立匿名函式的。GCC 4.5.x 和 Micro

C++11特性Lambda函式

我是搞C++的 一直都在提醒自己,我是搞C++的;但是當C++11出來這麼長時間了,我卻沒有跟著隊伍走,發現很對不起自己的身份,也還好,發現自己也有段時間沒有寫C++程式碼了。今天看到了C++中的Lambda表示式,雖然用過C#的,但是C++的,一直沒有用,也不知道怎麼

C++11特性function, bind和lambda

function, bind和lambda:bind中使用std::ref和std::cref,bind中預設使用的拷貝,而不是引用,根據實際情況,可使用std::ref和std::cref將引數設定為引用lambda:下面我們來總結下所有出現的 lambda 引入符:[]

15、【C++】C++11特性Lamda表示式/可變引數模板

一、Lamda表示式     Lamda表示式是C++11中引入的一項新技術,利用Lamda表示式可以編寫內嵌的匿名函式,用以替換獨立函式或者函式物件,並且使得程式碼更可讀。是一種匿名函式,即沒有函式名的函式;Lamda函式的語法定義如下: [capture] :捕捉

C++11特性移動語義和右值引用

右值引用 傳統的C++引用(左值引用)使得識別符號關聯到左值。左值是一個表示資料的表示式(如變數名或解除引用的指標),程式可以獲得其地址。 C++11新增了右值引用。右值引用,顧名思義,可以關聯到右值,即——可以出現在賦值表示式的右邊,但不能對其應用地址運算

C++11特性尾置返回型別

尾置返回型別是在C++11標準中新增的語法,可以用於任何函式定義中,旨在方便複雜函式的定義。尾置返回型別跟在形參列表後面並以一個->符號開頭。為了表示函式真正的返回型別跟在形參列表之後,需要在本應該出現返回型別的地方放置一個auto關鍵字。//宣告一個返回指向陣列的指

PostgreSQL 11 特性之覆蓋索引Covering Index

文章目錄 通常來說,索引可以用於提高查詢的速度。通過索引,可以快速訪問表中的指定資料,避免了表上的掃描。 有時候,索引不僅僅能夠用於定位表中的資料。某些查詢可能只需要訪問索引的資料,就能夠獲取所需要的結果,而不需要再次訪問表中的資料。這種訪問資料的方法叫做 In

C++11特性11- 標準庫函式begin和end

遍歷陣列元素的方法假設有一個數組:inta1[]{1,2,3,4,5};遍歷陣列的所有元素,可以這樣:for(unsignedinti=0;i<sizeof(a1)/sizeof(a1[0]);++i){cout<<a1[i]<<endl;}也可

C++11特性51- 移動建構函式通常應該是noexcept

不會丟擲異常的移動建構函式 拷貝建構函式通常伴隨著記憶體分配操作,因此很可能會丟擲異常;移動建構函式一般是移動記憶體的所有權,所以一般不會丟擲異常。 C++11中新引入了一個noexcept關鍵字,用來向程式設計師,編譯器來表明這種情況。 noexc

c++11 特性實戰 多執行緒操作

# c++11 新特性實戰 (一) ## c++11多執行緒操作 * 執行緒 * **thread** ```c++ int main() { thread t1(Test1); t1.join(); thread t2(Test2);

c++11特性實戰智慧指標

## c++11新特性實戰(二):智慧指標 c++11添加了新的智慧指標,unique_ptr、shared_ptr和weak_ptr,同時也將auto_ptr置為廢棄(deprecated)。 但是在實際的使用過程中,很多人都會有這樣的問題: 1. 不知道三種智慧指標的具體使用場景 2. 無腦只使用

C++11特性之 std::forward(完美轉發)

tails array sin .com std utili res details calling 我們也要時刻清醒,有時候右值會轉為左值,左值會轉為右值。 (也許“轉換”二字用的不是很準確) 如果我們要避免這種轉換呢? 我們需要一種方法能按照參數原來的類型轉發到另一個函

C++11特性——lambda表達式

amp 多個 str exp href 似的 exception 定義 參數傳遞 C++11的一大亮點就是引入了Lambda表達式。利用Lambda表達式,可以方便的定義和創建匿名函數。對於C++這門語言來說來說,“Lambda表達式”或“匿名函數”這些概念聽起來好像很深奧

C++11特性(80)-繼承的建構函式與多重繼承

複習 本文算是前面文章的繼續。 對於繼承的建構函式,C++11通過一個簡單的using語句,使得繼承一個類時可以省去一些麻煩。具體可以參照下面的文章。 C++11新特性(59)-繼承的建構函式 https://mp.weixin.qq.com/s/BGUa7-RSCtFRnBYj

C++11特性——default函式和deleted函式

轉自:http://blog.jobbole.com/103669/ default函式 default函式作用於類的特殊成員函式,為其自動生成預設的函式定義體,提高程式碼的執行效率。 類的特殊成員函式: 預設建構函式 解構函式 複

C++11特性之十enable_shared_from_this

 enable_shared_from_this是一個模板類,定義於標頭檔案<memory>,其原型為: template< class T > class enable_shared_from_this;        std::enable_s

C++11特性

auto關鍵字 C語言中其實就有auto關鍵字,修飾可變化的量,但是由於平時我們直接使用int a = 10;也是宣告變數,編譯器已經自動幫我們加上了auto關鍵字,是C語言中應用最廣泛的一種型別,也就是說,省去型別說明符auto的都是自動變數! 隨著時代進步,

C++11 特性之右值引用和轉移建構函式

問題背景 #include <iostream> usingnamespace std;   vector<int> doubleValues (const vector<int>& v)   {  

C++11特性總結列舉+繼承+左右值引用+變長模板

一、列舉+斷言+異常 // C++11的一些新的特性 #include "stdafx.h" #include <cassert> using namespace std; // C++