C++——lambda表达式
介紹
lambda表達(dá)式是一種局部類類型,它含有一個(gè)構(gòu)造函數(shù),和一個(gè)const成員函數(shù)operator()()。
lambda表達(dá)式除了能做參數(shù)外,還能用于初始化一個(gè)聲明為auto或者std::function<R(LA)>的變量。R是lambda的返回類型,LA是它的類型參數(shù)列表。
組成部件
實(shí)現(xiàn)模型
對(duì)于lambda表達(dá)式而言,有著很多種表述方法,并且有著多中優(yōu)化途徑。如果把lambda表達(dá)式看成是一種定義并使用函數(shù)對(duì)象的便捷方式,那么便于理解。
假設(shè)有這么一個(gè)例子:
void print_modulo(const vector<int>& v, ostream& os, int m) {for_each(begin(v), end(v),[&os, m](int x) {if (x % m == 0) os << x << '/n';}); }我們可以將其中的lambda表達(dá)式改寫成一個(gè)函數(shù)對(duì)象:
class Modulo_print {ostream& os;int m; public :Modulo_print(ostream& s, int mm) :os{ s }, m{ mm } {}void operator() (int x) const {if (x % m == 0) os << x << '/n';} };并且改寫之前的例子:
void print_modulo(const vector<int>& v, ostream& os, int m) {for_each(begin(v), end(v),Modulo_print{os, m}); }我們把由lambda表達(dá)式生成的函數(shù)對(duì)象稱為閉包對(duì)象 (閉包)。
如果lambda表達(dá)式通過(guò)引用 ([&]) 捕獲它定義環(huán)境中的每一個(gè)局部變量,則其閉包對(duì)象則可以優(yōu)化為簡(jiǎn)單的包含一個(gè)指向外層棧框架的指針。
捕獲
lambda表達(dá)式的主要用途是封裝一部分代碼以便將其用做參數(shù)。
有些lambda表達(dá)式無(wú)需訪問(wèn)它的局部環(huán)境,這樣lambda表達(dá)式使用空引入符 [ ] 定義。
lambda引入符的形式有很多:
對(duì)于lambda表達(dá)式來(lái)說(shuō),當(dāng)把lambda傳遞給另一個(gè)線程時(shí),用值捕獲更優(yōu),通過(guò)引用或者指針訪問(wèn)其他線程中的內(nèi)容是一種危險(xiǎn)操作,對(duì)于性能和正確性來(lái)說(shuō)都是如此。
對(duì)于可變模板參數(shù)的捕獲示例:
template <typename...Var> void algo(int s, Var... var) { auto helper = [&s, &var...]{return s * (h1(var...) + h2(var...)); }; }生命周期
lambda表達(dá)式的生命周期可能比它的被調(diào)用者更長(zhǎng)。當(dāng)我們把lambda表達(dá)式傳遞給另一個(gè)線程或者存在別處以供后續(xù)使用的時(shí)候。
例如:
當(dāng)setup完成之后,我們可能需要畫一個(gè)三角型,此時(shí)lambda表達(dá)式將會(huì)訪問(wèn)一個(gè)已經(jīng)不存在的局部變量。
如果我們發(fā)現(xiàn)一個(gè)lambda表達(dá)式的生命周期可能比它的調(diào)用者更長(zhǎng),則我們需要確保所有局部信息都已經(jīng)被拷貝到閉包對(duì)象中去。
m.add("draw a triangle", [=]{m.draw(p1, p2, p3); });lambda與this
當(dāng)lambda表達(dá)式被用在成員函數(shù)當(dāng)中,我們?cè)鯓尤ピL問(wèn)類成員變量呢?我們通過(guò)捕獲this指針來(lái)訪問(wèn)類成員對(duì)象。
例如:
類成員變量是通過(guò)this訪問(wèn)的,在lambda表達(dá)式中[this] 和 [=] 互不兼容,因此一不小心就可能在多線程程序中造成競(jìng)爭(zhēng)條件。
mutable的lambda表達(dá)式
如果希望在lambda表達(dá)式修改函數(shù)對(duì)象的狀態(tài),即修改通過(guò)值捕獲的變量,則可以使用mutable修飾符:
void algo() {int count = 100;[count]()mutable {return --count;}; }lambda表達(dá)式與返回類型
lambda表達(dá)式的大多數(shù)規(guī)則都是從類和函數(shù)借鑒過(guò)來(lái)的,然而需要有兩點(diǎn)需要注意:
如果在一條lambda表達(dá)式的主體部分不包含return語(yǔ)句,則其返回類型為void。
如果lambda表達(dá)式只包含一條return語(yǔ)句,則返回類型是return表達(dá)式的類型。 其他情況,必須顯式定義一個(gè)返回類型。
lambda表達(dá)式的類型
任意兩個(gè)lambda表達(dá)式的類型都不相同,一旦兩個(gè)lambda表達(dá)式的類型相同,則模板實(shí)例化機(jī)制就無(wú)法識(shí)別它們了。
例如:
auto algo = [&algo](char* b, char* a) {swap(*b, *--a); algo(++b, a);};由于algo的類型并沒(méi)有在使用之前被推斷出來(lái),因此上面的寫法是錯(cuò)誤的。
使用function包裝器可以存入函數(shù)對(duì)象。就可以保證,在使用之前, algo的類型就已經(jīng)知道了。
function<void (char*b, char*a)> algo = [&](char* b, char* a) {swap(*b, *--a); algo(++b, a);};如果我們只是想給lambda表達(dá)式起個(gè)名字,而不會(huì)在主體內(nèi)部遞歸的使用它。則:
auto algo = [&](char* b, char* a) {swap(*b, *--a); };是沒(méi)有問(wèn)題的。
如果lambda表達(dá)式什么也不捕獲,則我們可以把它賦值給一個(gè)指向正確類型的函數(shù)指針。
double (*fun) (double a) = [](double a) {return sqrt(a);};但行好事, 莫問(wèn)前程!
總結(jié)
以上是生活随笔為你收集整理的C++——lambda表达式的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 粗糙表面的微表面模型——Physical
- 下一篇: 《海岛大亨》厂商新作开售 回顾铁路上的美