lambda其實(shí)就是匿名函數(shù),有時候我們創(chuàng)建一個函數(shù),只有一個地方使用這個函數(shù)。或者某類函數(shù)的函數(shù)體經(jīng)常變化,需要動態(tài)生成。
我們沒必要按照正常創(chuàng)建其他函數(shù)一樣,所以可以使用lambda表達(dá)式。
語法格式
[Capture](paramlist) mutable throw() -> reutrnType
{
? ? 函數(shù)體;
}
一個完整的lambda表達(dá)式總共有六部分,其中部分是可以省略的?;旧衔覀兛吹絣ambda表達(dá)式和上面都是不一樣的,就是因?yàn)槠渲心骋徊糠只蚰硯撞糠直皇÷粤说木壒?
1. 捕獲子句
2. 參數(shù)列表?
3. 可變規(guī)范(可省略)
4. 異常規(guī)范(可省略)
5. 尾隨-返回類型(可省略)
6. lambda 體
來看一個例子:
我定義一個函數(shù)來操作A、B兩個整數(shù),具體的操作類型提前不能確定下來,而只能在實(shí)際使用的地方去定義。
詳細(xì)介紹
下面對每一部分都進(jìn)行一個詳細(xì)的介紹。
一、捕獲子句
捕獲子句的意思就是你可以在lambda方法體內(nèi)使用外部的變量。
如上面的例子:我在main方法里面定義了一個局部變量,那么,我就可以在捕獲子句中把它傳給lambda表達(dá)式方法體內(nèi)。我在整個文件中定義了一個全局變量,也可以把它在捕獲子句中傳給lambda方法體內(nèi)。
int main()
{
? ? int count = 6;
? ? // 把count傳入lambda表達(dá)式中
? ? int result = operAandB(1, 2, [count](int a, int b) {return a + b + count;});
? ? printf("result is %d\n", result);
? ? int result1 = operAandB(1, 2, [](int a, int b) {return a * b;});
? ? printf("result1 is %d\n", result1);
}
當(dāng)然,把外部變量傳入lambda表達(dá)式中,語法不同,其代表的含義也不同,具體可以分為這么幾種情況。
1. 捕獲子句部分不能省略,即使你不需要捕獲任何變量,也要寫一個[]
2. 多個捕獲變量用逗號(,)隔開
int count = 6;
int num = 2;
int result = operAandB(1, 2, [count, num](int a, int b) {return a + b + count + num;});
3. 支持通過&捕獲引用,這樣在lambda中對變量修改的同時外部變量也會發(fā)生變化
int count = 6;
int result = operAandB(1, 2, [&count](int a, int b) {count++; return a + b + count;});
// result是10, count變成7
printf("result is %d, count is %d\n", result, count);
4. 支持把this指針傳入lambda中
int Student::aPlusB(int a, int b)
{
? ? return operAandB(a, b, [this](int a, int b) {return a + b + this->age;});
}
也可以給this重命名一下
int Student::aPlusB(int a, int b)
{
? ? return operAandB(a, b, [student = this](int a, int b) {return a + b + student ->age;});
}
5. 支持按值傳遞的方式把變量傳到lambda表達(dá)式中。
? ? 按照值傳遞有兩種,一種情況下就是只寫上變量名字[a];另外就是在變量前面使用等號[=, a]。兩種情況是等價(jià)的。
std::string s = "abc";
// 這么寫
int result = operAandB(a, b, [s](int a, int b) mutable {s = "ab"; std::cout << s << std::endl; return a + b;});
// 或者這么寫
int result = operAandB(a, b, [=, s](int a, int b) mutable {s = "ab"; std::cout << s << std::endl; return a + b;});
std::cout << s << std::endl;
二、參數(shù)列表
參數(shù)列表就很好解釋了。就是你編寫一個函數(shù)要傳入的形參列表,這個和普通的函數(shù)編寫是一樣的: (參數(shù)類型 參數(shù)名)
// int a, int b就是參數(shù)列表
[s](int a, int b) mutable {s = "ab"; std::cout << s << std::endl; return a + b;}
三、可變規(guī)范
可變規(guī)范是和捕獲子句結(jié)合在一起使用。在捕獲子句的第五種情況按值傳遞時,如果我們在lambda表達(dá)式中想對傳入的變量進(jìn)行修改,就需要加上關(guān)鍵詞mutable。否則編譯的時候會報(bào)錯。
需要注意的是對變量的改變只是在lambda函數(shù)體中生效,外部原有的變量則不受影響。
std::string s = "abc";
// 此處在lambda中打印出來的s的值是ab
int result = operAandB(a, b, [s](int a, int b) {s = "ab"; std::cout << s << std::endl; return a + b;});
// 外部的變量并不受影響,此處仍然是abc
std::cout << s << std::endl;
四、異常規(guī)范
目前大部分的c++編碼規(guī)范都不允許拋出異常,所以這里我沒用過,直接把官網(wǎng)的解釋復(fù)制過來了。
您可以使用?noexcept?異常規(guī)范來指示 lambda 表達(dá)式不會引發(fā)任何異常。 與普通函數(shù)一樣,如果 lambda 表達(dá)式聲明?noexcept?異常規(guī)范且 lambda 體引發(fā)異常,Microsoft c + + 編譯器將生成警告 C4297,如下所示:
// throw_lambda_expression.cpp
// compile with: /W4 /EHsc
int main() // C4297 expected
{
? ? []()noexcept{throw5; }();
}
五、返回類型
返回類型就是lambda函數(shù)體的返回值,可省略,c++會對返回值進(jìn)行自動推導(dǎo)。
如果顯式寫明返回值,需要在返回值前使用->連接。
int result = operAandB(a, b, [](int a, int b) -> int {return a + b;});
六、lambda 體
lambda體就是我們的函數(shù)體,在里面編寫我們的函數(shù)處理代碼。這里和寫普通函數(shù)也是一樣的。
{
? ? int result = a + b;
? ? return result;
}
總結(jié):
lambda表達(dá)式作為一個匿名函數(shù),和編寫一個普通函數(shù)的區(qū)別不大,主要集中在第一、第三部分,因此文中花了大量的筆墨去介紹。其余和普通函數(shù)一樣的地方,就盡量簡單帶過,防止過多贅述給大家造成誤解。
由于水平的問題,文中部分可能存在表述有誤的情況,歡迎大家指正。