1. lambda表達式的定義形式
lambda表達式是C++11引入的一個重要特性之一密强,來源于函數(shù)式編程的概念帅掘。一個lambda表達式就是一個可調(diào)用的代碼單元壁顶,lambda表達式的定義形式如下:
[captrue list] (parameter list) -> return type or exception { function body}
- captrue list 捕獲列表际乘;
- parameter list 參數(shù)列表副砍;
- "-> return type" 尾置返回類型衔肢,或者異常;
- function body 函數(shù)體豁翎;
image.png
當(dāng)編寫一個lambda表達式之后角骤,編譯器將該表達式翻譯成一個未命名類的未命名對象,在lambda表達式產(chǎn)生的未命名類中含有一個重載的函數(shù)調(diào)用運算符,如:
// lambda表達式
auto func = [](const string &a, const string &b){
return a.size() > b.size();
};
// 等價于
class NoNameClass{
public:
bool operator()(const string &a, const string &b) const{
return a.size() > b.size();
}
};
2. lambda表達式使用注意細節(jié)
- 與普通函數(shù)不同邦尊,lambda表達式的參數(shù)列表不能有默認(rèn)值背桐;
- lambda可以省略參數(shù)列表和返回類型(默認(rèn)返回void),但是必須包含捕獲列表和函數(shù)體蝉揍;
- 默認(rèn)情況下链峭,如果一個lambda中包含一個return之外的任何語句,編譯器將假定此lambda的返回void又沾;
- lambda若有返回類型弊仪,只能通過尾置返回的方法指定返回類型;
// 只包含一個return語句的lambda表達式杖刷,返回類型會自動推導(dǎo)
auto f = []{ return 42; };
// 包含了除retrun以外的其他語句励饵,必須通過尾置的方式指定返回類型
auto f = [](int i) -> int // 尾置返回值類型
{
if (i<0) return -i; else return i;
};
- 捕獲列表只用于局部非static變量,lambda表達式可以直接使用局部static變量和它所在函數(shù)之外聲明的名字滑燃;
3. 捕獲列表
值捕獲
lambda表達式通過值捕獲時役听,捕獲的值會被拷貝到產(chǎn)生的無名類的對象中,無名類中應(yīng)包含與之對應(yīng)的數(shù)據(jù)成員不瓶。
例如:查找一個單詞列表中禾嫉,第一個長度大于10的單詞
// lambda表達式
size_t szvalue = 10;
find_if(words.begin(), words.end(),
[sz](const string &a){returna.size() > szvalue ;});
// 等價于
class NoNameClass{
public:
NoNameClass(size_t n): sz(n){} //增加了一個構(gòu)造函數(shù)
bool operator()(const string &a) const{
return a.size() > sz;
}
private:
size_t sz; // 增加了對應(yīng)的成員變量
};
find_if(words.begin(), words.end(), NoNameClass(szvalue ));
因此下面的例子就不難理解了,
void func1()
{
size_t v1 = 41;
auto f = [v1]{return v1;};
v1 = 0;
cout << f() << endl; //輸出42蚊丐,因為此時相當(dāng)于打印的是無名對象中的成員變量;
}
注意:lambda表達式產(chǎn)生的類中不含默認(rèn)的構(gòu)造函數(shù)艳吠、賦值運算符麦备、以及默認(rèn)的析構(gòu)函數(shù)。
引用捕獲
當(dāng)lambda表達式通過引用捕獲變量時昭娩,編譯器直接使用該引用凛篙,而不會在lambda產(chǎn)生的無名類中將其保存為成員變量,因此程序需要負(fù)責(zé)確保lambda表達式執(zhí)行時栏渺,所引用的對象確實存在呛梆。
void func2()
{
size_t v1 = 41;
auto f = [&v1]{return v1;};
v1 = 0;
cout << f() << endl; //輸出0
}
一般來說,應(yīng)該盡量減少捕獲的數(shù)據(jù)磕诊,來避免潛在的捕獲導(dǎo)致的問題填物。而且,如果可能的話霎终,應(yīng)該盡量避免捕獲引用或者指針滞磺。
隱式捕獲
在捕獲列表中寫一個&或者=,編譯器會自動的推斷使用哪種捕獲方式莱褒,&使用引用的方式捕獲击困,=則表示使用值的方式捕獲。
如果希望對一部分變量采用值捕獲广凸,對其他變量采用引用捕獲阅茶,可以混合使用隱式捕獲和顯示捕獲蛛枚。
image.png
參考
- C++ Primer (第五版)