轉(zhuǎn)自:https://www.devbean.net/2012/05/cpp11-lambda/
或許,Lambda 表達(dá)式算得上是 C++ 11 新增特性中最激動(dòng)人心的一個(gè)。這個(gè)全新的特性聽起來很深?yuàn)W,但卻是很多其他語言早已提供(比如 C#)或者即將提供(比如 java)的。簡(jiǎn)而言之,Lambda 表達(dá)式就是用于創(chuàng)建匿名函數(shù)的。GCC 4.5.x 和 Microsoft Visual Studio 早已提供了對(duì) lambda 表達(dá)式的支持。在 GCC 4.7 中,默認(rèn)是不開啟 C++ 11 特性的,需要添加 -std=c++11 編譯參數(shù)。而 VS2010 則默認(rèn)開啟。
為什么說 lambda 表達(dá)式如此激動(dòng)人心呢?舉一個(gè)例子。標(biāo)準(zhǔn) C++ 庫(kù)中有一個(gè)常用算法的庫(kù),其中提供了很多算法函數(shù),比如 sort() 和 find()。這些函數(shù)通常需要提供一個(gè)“謂詞函數(shù) PRedicate function”。所謂謂詞函數(shù),就是進(jìn)行一個(gè)操作用的臨時(shí)函數(shù)。比如 find() 需要一個(gè)謂詞,用于查找元素滿足的條件;能夠滿足謂詞函數(shù)的元素才會(huì)被查找出來。這樣的謂詞函數(shù),使用臨時(shí)的匿名函數(shù),既可以減少函數(shù)數(shù)量,又會(huì)讓代碼變得清晰易讀。
下面來看一個(gè)例子:
#include <algorithm>#include <cmath>void abssort(float *x, unsigned N){ std::sort(x, x + N, [](float a, float b) { return std::abs(a) < std::abs(b); });}從上面的例子來看,盡管支持 lambda 表達(dá)式,但 C++ 的語法看起來卻很“神奇”。lambda 表達(dá)式使用一對(duì)方括號(hào)作為開始的標(biāo)識(shí),類似于聲明一個(gè)函數(shù),只不過這個(gè)函數(shù)沒有名字,也就是一個(gè)匿名函數(shù)。這個(gè)匿名函數(shù)接受兩個(gè)參數(shù),a和b;其返回值是一個(gè) bool 類型的值,注意,返回值是自動(dòng)推斷的,不需要顯式聲明,不過這是有條件的!條件就是,lambda 表達(dá)式的語句只有一個(gè) return。函數(shù)的作用是比較 a、b 的絕對(duì)值的大小。然后,在此例中,這個(gè) lambda 表達(dá)式作為一個(gè)閉包被傳遞給 std::sort() 函數(shù)。
下面,我們來詳細(xì)解釋下這個(gè)神奇的語法到底代表著什么。
我們從另外一個(gè)例子開始:
std::cout << [](float f) { return std::abs(f); } (-3.5);輸出值是什么?3.5!注意,這是一個(gè)函數(shù)對(duì)象(由 lambda 表達(dá)式生成),其實(shí)參是 -3.5,返回值是參數(shù)的絕對(duì)值。lambda 表達(dá)式的返回值類型是語言自動(dòng)推斷的,因?yàn)閟td::abs()的返回值就是 float。注意,前面我們也提到了,只有當(dāng) lambda 表達(dá)式中的語句“足夠簡(jiǎn)單”,才能自動(dòng)推斷返回值類型。
C++ 11 的這種語法,其實(shí)就是匿名函數(shù)聲明之后馬上調(diào)用(否則的話,如果這個(gè)匿名函數(shù)既不調(diào)用,又不作為閉包傳遞給其它函數(shù),那么這個(gè)匿名函數(shù)就沒有什么用處)。如果你覺得奇怪,那么來看看 JavaScript 的這種寫法:
function() {} ();function(a) {} (-3.5);C++ 11 的寫法完全類似 Javascript 的語法。
如果我不想讓 lambda 表達(dá)式自動(dòng)推斷類型,或者是 lambda 表達(dá)式的內(nèi)容很復(fù)雜,不能自動(dòng)推斷怎么辦?比如,std::abs(float)的返回值是 float,我想把它強(qiáng)制轉(zhuǎn)型為 int。那么,此時(shí),我們就必須顯式指定 lambda 表達(dá)式返回值的類型:
std::cout << [](float f) -> int { return std::abs(f); } (-3.5);這個(gè)語句與前面的不同之處在于,lambda 表達(dá)式的返回時(shí)不是 float 而是 int。也就是說,上面語句的輸出值是 3。返回值類型的概念同普通的函數(shù)返回值類型是完全一樣的。
當(dāng)我們想引用一個(gè) lambda 表達(dá)式時(shí),我們可以使用auto關(guān)鍵字,例如:
auto lambda = [] () -> int { return val * 100; };auto關(guān)鍵字實(shí)際會(huì)將 lambda 表達(dá)式轉(zhuǎn)換成一種類似于std::function的內(nèi)部類型(但并不是std::function類型,雖然與std::function“兼容”)。所以,我們也可以這么寫:
std::function<int()> lambda = [] () -> int { return val * 100; };如果你對(duì)std::function
float f0 = 1.0;std::cout << [=](float f) { return f0 + std::abs(f); } (-3.5);其輸出值是 4.5。[=] 意味著,lambda 表達(dá)式以傳值的形式捕獲同范圍內(nèi)的變量。另外一個(gè)例子:
float f0 = 1.0;std::cout << [&](float f) { return f0 += std::abs(f); } (-3.5);std::cout << '/n' << f0 << '/n';輸出值是 4.5 和 4.5。[&] 表明,lambda 表達(dá)式以傳引用的方式捕獲外部變量。那么,下一個(gè)例子:
float f0 = 1.0;std::cout << [=](float f) mutable { return f0 += std::abs(f); } (-3.5);std::cout << '/n' << f0 << '/n';這個(gè)例子很有趣。首先,[=]意味著,lambda 表達(dá)式以傳值的形式捕獲外部變量。C++ 11 標(biāo)準(zhǔn)說,如果以傳值的形式捕獲外部變量,那么,lambda 體不允許修改外部變量,對(duì) f0 的任何修改都會(huì)引發(fā)編譯錯(cuò)誤。但是,注意,我們?cè)?lambda 表達(dá)式前聲明了mutable關(guān)鍵字,這就允許了 lambda 表達(dá)式體修改 f0 的值。因此,我們的例子本應(yīng)報(bào)錯(cuò),但是由于有 mutable 關(guān)鍵字,則不會(huì)報(bào)錯(cuò)。那么,你會(huì)覺得輸出值是什么呢?答案是,4.5 和 1.0。為什么 f0 還是 1.0?因?yàn)槲覀兪莻髦档模m然在 lambda 表達(dá)式中對(duì) f0 有了修改,但由于是傳值的,外部的 f0 依然不會(huì)被修改。
上面的例子是,所有的變量要么傳值,要么傳引用。那么,是不是有混合機(jī)制呢?當(dāng)然也有!比如下面的例子:
float f0 = 1.0f;float f1 = 10.0f;std::cout << [=, &f0](float a) { return f0 += f1 + std::abs(a); } (-3.5);std::cout << '/n' << f0 << '/n';這個(gè)例子的輸出是 14.5 和 14.5。在這個(gè)例子中,f0 通過引用被捕獲,而其它變量,比如 f1 則是通過值被捕獲。
下面我們來總結(jié)下所有出現(xiàn)的 lambda 引入符:
[] // 不捕獲任何外部變量[=] // 以值的形式捕獲所有外部變量[&] // 以引用形式捕獲所有外部變量 [x, &y] // x 以傳值形式捕獲,y 以引用形式捕獲 [=, &z]// z 以引用形式捕獲,其余變量以傳值形式捕獲 [&, x] // x 以值的形式捕獲,其余變量以引用形式捕獲另外有一點(diǎn)需要注意。對(duì)于[=]或[&]的形式,lambda 表達(dá)式可以直接使用 this 指針。但是,對(duì)于[]的形式,如果要使用 this 指針,必須顯式傳入:.
[this]() { this->someFunc(); }();至此,我們已經(jīng)大致了解了 C++ 11 提供的 lambda 表達(dá)式的概念。建議通過結(jié)合 lambda 表達(dá)式與std::sort()或std::for_each()這樣的標(biāo)準(zhǔn)函數(shù)來嘗試使用一下吧!
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注