1舵揭、介紹
lambda表達(dá)式常用于向函數(shù)傳遞謂詞药磺,有些函數(shù)的參數(shù)只能接受一元謂詞(如find_if)辅柴,但是如果我們需要向函數(shù)傳遞二元謂詞,這時(shí)候可以使用lambda表達(dá)式(匿名函數(shù))怠噪,lambda表達(dá)式是重載了運(yùn)算符[]的函數(shù)恐似。
2、lambda表達(dá)式的使用
一個(gè)lambda表達(dá)式表示一個(gè)可調(diào)用的代碼單元傍念,我們可以將其理解為一個(gè)未命名的內(nèi)聯(lián)函數(shù)矫夷。與函數(shù)相似,一個(gè)lambda表達(dá)式具有一個(gè)返回類(lèi)型憋槐、一個(gè)參數(shù)列表和一個(gè)函數(shù)體双藕。一個(gè)lambda表達(dá)式具有如下的形式:
[捕獲參數(shù)](參數(shù)列表) -> 返回類(lèi)型 {函數(shù)體}
lambda表達(dá)式必須使用尾置返回類(lèi)型。
(1)簡(jiǎn)單的lambda表達(dá)式
auto func = [] {return 42;};
上式中忽略了參數(shù)列表和返回類(lèi)型阳仔,但是必須包含捕獲列表和函數(shù)體忧陪。
cout <<func() <<endl; //調(diào)用func的方式和普通函數(shù)類(lèi)似,此式輸出42.
(2)含有參數(shù)的lambda表達(dá)式
向lambda表達(dá)式傳遞參數(shù)的時(shí)候驳概,和普通函數(shù)類(lèi)似赤嚼,但是lambda表達(dá)式不能含有默認(rèn)值旷赖,因此傳遞參數(shù)的時(shí)候?qū)崊⑴c形參一定相等顺又。
完成isShorter函數(shù)的lambda表達(dá)式如下:
[] (const string& a, const string& b) { return a.size() < b.size(); }
空捕獲列表表示lambda表達(dá)式不使用其所在函數(shù)的局部變量。上述的lambda表達(dá)式調(diào)用的時(shí)候會(huì)進(jìn)行比較兩個(gè)參數(shù)的長(zhǎng)短等孵,并返回bool值稚照。
在stable_sort()函數(shù)中使用上述的lambda表達(dá)式:
stable_sort(words.begin(), words.end(), [] (const string& a, const string& b) { return a.size() < b.size(); });
這樣stable_sort函數(shù)在排序的時(shí)候就會(huì)調(diào)用lambda表達(dá)式,按字符串長(zhǎng)度從小到大排列俯萌。
注:一個(gè)lambda表達(dá)式如果如果忽略返回類(lèi)型果录,那么lambda表達(dá)式會(huì)根據(jù)函數(shù)體的返回值推斷類(lèi)型,但是前提是函數(shù)體只有一個(gè)return語(yǔ)句咐熙;如果lambda表達(dá)式忽略了返回類(lèi)型弱恒,并且函數(shù)體不有return語(yǔ)句之外的語(yǔ)句,那么返回類(lèi)型是void棋恼。
(3)使用捕獲列表的lambda表達(dá)式
lambda表示一般是用于函數(shù)中返弹,如果lambda表達(dá)式需要使用到函數(shù)中的局部變量,則需要是用捕獲列表進(jìn)行捕獲爪飘。
如:使用find_if函數(shù)查找第一個(gè)滿足字符串長(zhǎng)度大于len的字符义起。
int len = 5;
stable_sort(words.begin(), words.end(), [] (const string& a, const string& b) { return a.size() < b.size(); });
find_if(words.begin(), words.end(), [len](const string& a) { return a.size() > len; });
上述例子中find_if函數(shù)中的第三個(gè)參數(shù)傳遞了一個(gè)lambda表達(dá)式,該表達(dá)式使用捕獲列表捕獲了參數(shù)len师崎,對(duì)words中的每一個(gè)元素的長(zhǎng)度和len進(jìn)行比較默终,返回第一個(gè)長(zhǎng)度大于len的字符串的迭代器。
(4)值捕獲與引用捕獲
值捕獲:
lambda表達(dá)式采用[name]的形式捕獲參數(shù)的時(shí)候,便是使用的值捕獲齐蔽。采用值捕獲的前提是參數(shù)能夠拷貝两疚。與函數(shù)參數(shù)不同,被捕獲的變量的值是在lambda表達(dá)式創(chuàng)建的時(shí)候拷貝的肴熏,而不是調(diào)用時(shí)拷貝鬼雀。
int i = 40;
auto func = [i] {return i;};
i = 0;
auto j = func(); //此時(shí)變量j=40,func保存了我們創(chuàng)建它時(shí)i的拷貝
引用捕獲:
引用捕獲和變量的引用類(lèi)似蛙吏,在lambda表達(dá)式中采用引用捕獲源哩,那么在lambda表達(dá)式使用的便是引用所綁定的對(duì)象的值。如果采用引用捕獲鸦做,我們必須確保被引用的對(duì)象在lambda表達(dá)式執(zhí)行的時(shí)候是存在的励烦。
int i = 40;
auto func = [&i] {return i;};
i = 0;
auto j = func(); //此時(shí)變量j=0,func保存的是i的引用泼诱,沒(méi)有拷貝坛掠。
隱式捕獲:
可以用=和&表示lambda表達(dá)式是采用值捕獲還是引用捕獲
find_if(words.begin(), words.end(), [=](const string& a) { return a.size() > len; });
使用=號(hào)表示采用的是值捕獲(lambda表達(dá)式中所有的參數(shù)都是)。
find_if(words.begin(), words.end(), [&](const string& a) { return a.size() > len; });
使用&號(hào)表示采用的是引用捕獲(lambda表達(dá)式中所有的參數(shù)都是)治筒。
顯式和隱式捕獲混用:
for_each(words.begin(), words.end(), [&, c] (const string &a) { os<< a << c; });
上面的lambda表達(dá)式中顯式聲明變量c采用值捕獲的方式屉栓,其余變量采用引用捕獲。
for_each(words.begin(), words.end(), [=, &os] (const string &a) { os<< a << c; });
上面的lambda表達(dá)式中顯式聲明變量os采用引用捕獲的方式耸袜,其余變量采用值捕獲友多。
(5)指定lambda表達(dá)式的返回類(lèi)型
如前所述,如果要指定lambda表達(dá)式的返回值類(lèi)型堤框,必須使用尾置返回類(lèi)型域滥。
transform(v.begin(), v.end(), v.begin(), [](int i) { return i < 0 ? i : -i; });
上面的表達(dá)式是將數(shù)組v中的負(fù)數(shù)替換為絕對(duì)值,因?yàn)閘ambda表達(dá)式中只有一個(gè)return 語(yǔ)句蜈抓,因此可以不指定返回類(lèi)型启绰,編譯器會(huì)自動(dòng)推斷返回類(lèi)型為int。
但是若修改成:
transform(v.begin(), v.end(), v.begin(), [](int i) { if(i < 0) return -i; else return i;});
則會(huì)發(fā)生編譯報(bào)錯(cuò)沟使。需要采用尾置返回類(lèi)型修改委可。
transform(v.begin(), v.end(), v.begin(), [] (int i) -> int { if(i < 0) return -i; else return i;});
這樣便指定了lambda表達(dá)式的返回類(lèi)型。
總結(jié):
(1)lambda表達(dá)式為匿名函數(shù)腊嗡,常用于在函數(shù)中傳遞謂詞着倾,如排序算法中傳遞是遞增排序還是遞減排序。
(2)lambda表達(dá)式采用引用捕獲參數(shù)的時(shí)候一定要保證在lambda表達(dá)式調(diào)用參數(shù)的時(shí)候變量一直存在叽唱。
(3)lambda表達(dá)式中如果只有一條return語(yǔ)句屈呕,返回類(lèi)型由編譯器自動(dòng)推斷;否則默認(rèn)返回void
(4)要指定lambda表達(dá)式的返回類(lèi)型要用尾置返回類(lèi)型棺亭。
(5)lambda表達(dá)式要盡量短;⒄!(類(lèi)似內(nèi)聯(lián)函數(shù))