本文根據(jù)眾多互聯(lián)網(wǎng)博客內(nèi)容整理后形成,引用內(nèi)容的版權(quán)歸原始作者所有,僅限于學(xué)習(xí)研究使用,不得用于任何商業(yè)用途。
C++11引入了lambda表達(dá)式,使得程序員可以定義匿名函數(shù),該函數(shù)是一次性執(zhí)行的,既方便了編程饲做,又能防止別人的訪問塞弊。
Lambda表達(dá)式的語法通過下圖來介紹:
這里假設(shè)我們定義了一個如上圖的lambda表達(dá)式。現(xiàn)在來介紹途中標(biāo)有編號的各個部分是什么意思。
- Lambda表達(dá)式的引入標(biāo)志游沿,在‘[]’里面可以填入‘=’或‘&’表示該lambda表達(dá)式“捕獲”(lambda表達(dá)式在一定的scope可以訪問的數(shù)據(jù))的數(shù)據(jù)時以什么方式捕獲的饰抒,‘&’表示以引用的方式;‘=’表明以值傳遞的方式捕獲诀黍,除非專門指出袋坑。
- Lambda表達(dá)式的參數(shù)列表
- Mutable 標(biāo)識
- 異常標(biāo)識
- 返回值
- “函數(shù)”體,也就是lambda表達(dá)式需要進(jìn)行的實際操作
Lambda表達(dá)式是一種描述函數(shù)對象的機(jī)制眯勾,它的主要應(yīng)用是描述某些具有簡單行為的函數(shù)(譯注:Lambda表達(dá)式也可以稱為匿名函數(shù)咒彤,具有復(fù)雜行為的函數(shù)可以采用命名函數(shù)對象,當(dāng)然,何謂復(fù)雜咒精,何謂簡單镶柱,這取決于編程人員的個人選擇)。例如:
vector<int> v = {50, -10, 20, -30};
std::sort(v.begin(), v.end()); // 排序時按照默認(rèn)規(guī)則
// 此時v中的數(shù)據(jù)應(yīng)該是 { -30, -10, 20, 50 }
// 利用Lambda表達(dá)式模叙,按照絕對值排序
std::sort(v.begin(), v.end(), [](int a, int b){ return abs(a)<abs(b); });
// 此時v應(yīng)該是 { -10, 20, -30, 50 }
函數(shù) [](int a, int b) { return abs(a) < abs(b); }
是一個具有如下行為的"lambda":接受兩個整數(shù)a和b歇拆,然后返回對它們的絕對值進(jìn)行"<"比較的結(jié)果。
Lambda表達(dá)式可以訪問在它被調(diào)用的作用域內(nèi)的局部變量范咨。例如:
void f(vector<Record>& v)
{
vector<int> indices(v.size());
int count = 0;
generate(indices.begin(),indices.end(),[&count]()
{ return count++; });
// 對indices按照記錄的名字域順序進(jìn)行排序
std::sort(indices.begin(), indices.end(), [&](int a, int b)
{ return v[a].name<v[b].name; });
// ...
}
有人認(rèn)為這“相當(dāng)簡潔”故觅,也有人認(rèn)為這是一種可能產(chǎn)生危險且晦澀的代碼的方式。我的看法是渠啊,兩者都正確输吏。
- [&] 是一個“捕捉列表(capture list)”,用于描述將要被lambda函數(shù)以引用傳參方式使用的局部變量替蛉。
- 如果我們僅想“捕捉”參數(shù)v贯溅,則可以寫為: [&v]。
- 而如果我們想以傳值方式使用參數(shù)v躲查,則可以寫為:[=v]它浅。
- 如果什么都不捕捉,則為:[]镣煮。
- 將所有的變量以引用傳遞方式使用時采用[&], 而相對地姐霍,使用[=] 則相應(yīng)地表示以傳值方式使用所有變量。
(譯注:“所有變量”即指lambda表達(dá)式在被調(diào)用處典唇,所能見到的所有局部變量)
如果某一函數(shù)的行為既不通用也不簡單镊折,那么我建議采用命名函數(shù)對象或者函數(shù)。例如介衔,如上示例可重寫為:
void f( vector<Record>& v)
{
vector<int> indices(v.size() );
int count = 0;
fill(indices.begin(), indices.end(), [&]()
{ return ++count; };
struct Cmp_names {
const vector& vr;
Cmp_names(const vector<Record>& r) : vr(r) {}
bool operator() (Record& a, Record& b) const { return vr[a] < vr[b]; }
};
//對indices按照記錄的名字域順序進(jìn)行排序
std::sort(indices.begin(), indices.end(), Cmp_names(v) );
}
(譯注:此處采用了函數(shù)對象Cmp_names(v)來代替lambda表達(dá)式恨胚,由于Cmp_names具有以引用傳參方式的構(gòu)造函數(shù),因此Cmp_names(v)相當(dāng)于使用了”[&v]”的lambda表達(dá)式)
對于簡單的函數(shù)功能夜牡,比如記錄名稱域的比較与纽,采用函數(shù)對象就略顯冗長,盡管它與lambda表達(dá)式生成的代碼是一致的塘装。在C++98中急迂,這樣的函數(shù)對象在被用作模板參數(shù)時必須是“非本地”的(譯注:即你不能在函數(shù)對象中像此處的lambda表達(dá)式那樣使用被調(diào)用處的局部變量),然而在C++中(譯注:意指C++0x)蹦肴,這不再是必須的僚碎。
為了描述一個lambda,你必須提供:
- 它的捕捉列表:即(除了形參之外)它可以使用的變量列表(”[&]” 在上面的記錄比較例子中意味著“所有的局部變量都將按照引用的方式進(jìn)行傳遞”)阴幌。如果不需要捕捉任何變量勺阐,則使用 []。
- (可選的)它的所有參數(shù)及其類型(例如: (int a, int b))矛双。
- 組織成一個塊的函數(shù)行為(例如:{ return v[a].name < v[b].name; })渊抽。
- (可選的)使用”返回值類型后置語法“來指明返回類型。但典型情況下议忽,我們僅從return語句中去推斷返回類型懒闷,如果沒有返回任何值,則推斷為void栈幸。
int n = [] (int x, int y) { return x + y; }(5, 4);
cout << n << endl;
參考資料
Lambda表達(dá)式 | cpp11新特性詳解與應(yīng)用
Lambda表達(dá)式 | C++11 FAQ 中文版
C++11 lambda表達(dá)式 - KingsLanding
用作模板參數(shù)的局部類型 | C++11 FAQ 中文版