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++