[函數(shù)對(duì)象參數(shù)],例如[&,a,b]標(biāo)識(shí)一個(gè)Lambda的開(kāi)始,這部分必須存在,不能省略。函數(shù)對(duì)象參數(shù)是傳遞給編譯器自動(dòng)生成的函數(shù)對(duì)象類的構(gòu)造函數(shù)的。
函數(shù)對(duì)象參數(shù)有以下形式:
[ ] 空沒(méi)有使用任何函數(shù)對(duì)象參數(shù)。
[=] 函數(shù)體內(nèi)可以使用Lambda所在作用范圍內(nèi)所有可見(jiàn)的局部變量(包括Lambda所在類的this),并且是值傳遞方式(相當(dāng)于編譯器自動(dòng)為我們按值傳遞了所有局部變量)。
[&] 函數(shù)體內(nèi)可以使用Lambda所在作用范圍內(nèi)所有可見(jiàn)的局部變量(包括Lambda所在類的this),并且是引用傳遞方式(相當(dāng)于編譯器自動(dòng)為我們按引用傳遞了所有局部變量)。
[this] 函數(shù)體內(nèi)可以使用Lambda所在類中的成員變量。
[a] 將a按值進(jìn)行傳遞。按值進(jìn)行傳遞時(shí),函數(shù)體內(nèi)不能修改傳遞進(jìn)來(lái)的a的拷貝,因?yàn)槟J(rèn)情況下函數(shù)是const的。要修改傳遞進(jìn)來(lái)的a的拷貝,可以添加mutable修飾符。
[&a] 將a按引用進(jìn)行傳遞。
[a, &b] 將a按值進(jìn)行傳遞,b按引用進(jìn)行傳遞。
[=,&a, &b] 除a和b按引用進(jìn)行傳遞外,其他參數(shù)都按值進(jìn)行傳遞。
[&, a, b] 除a和b按值進(jìn)行傳遞外,其他參數(shù)都按引用進(jìn)行傳遞。
(操作符重載函數(shù)參數(shù)),例如(int a,int &b)標(biāo)識(shí)重載的()操作符的參數(shù),沒(méi)有參數(shù)時(shí),這部分可以省略。參數(shù)可以通過(guò)按值(如:(a,b))和按引用(如:(&a,&b))兩種方式進(jìn)行傳遞
mutable與exception聲明,例如 mutable throw(),可省略
按值傳遞函數(shù)對(duì)象參數(shù)時(shí),加上mutable修飾符后,可以修改按值傳遞進(jìn)來(lái)的拷貝(注意是能修改拷貝,而不是值本身,如果沒(méi)有添加mutable,相當(dāng)于對(duì)函數(shù)參數(shù)的增加了const修飾,無(wú)法修改參數(shù))。exception聲明用于指定函數(shù)拋出的異常,如拋出整數(shù)類型的異常,可以使用throw(int)。
示例:
->返回值類型,例如 ->int 表示返回 int類型
標(biāo)識(shí)函數(shù)返回值的類型,當(dāng)返回值為void,或者函數(shù)體中只有一處return的地方(此時(shí)編譯器可以自動(dòng)推斷出返回值類型)時(shí),這部分可以省略。
{函數(shù)體},例如{cout<<“abc”;},不可省略,可以為空
// 無(wú)函數(shù)對(duì)象參數(shù),輸出:1 2 { for_each(vctTemp.begin(), vctTemp.end(), [](int v){ cout << v << endl; }); }
// 以值方式傳遞作用域內(nèi)所有可見(jiàn)的局部變量(包括this),輸出:11 12 { int a = 10; for_each(vctTemp.begin(), vctTemp.end(), [=](int v){ cout << v+a << endl; }); }
// 以引用方式傳遞作用域內(nèi)所有可見(jiàn)的局部變量(包括this),輸出:11 13 12 { int a = 10; for_each(vctTemp.begin(), vctTemp.end(), [&](int v)mutable{ cout << v+a << endl; a++; }); cout << a << endl; }
// 以值方式傳遞局部變量a,輸出:11 13 10 { int a = 10; for_each(vctTemp.begin(), vctTemp.end(), [a](int v)mutable{ cout << v+a << endl; a++; }); cout << a << endl; }
// 以引用方式傳遞局部變量a,輸出:11 13 12 { int a = 10; for_each(vctTemp.begin(), vctTemp.end(), [&a](int v){ cout << v+a << endl; a++; }); cout << a << endl; }
// 傳遞this,輸出:21 22 { for_each(vctTemp.begin(), vctTemp.end(), [this](int v){ cout << v+m_nData << endl; }); }
// 除b按引用傳遞外,其他均按值傳遞,輸出:11 12 17 { int a = 10; int b = 15; for_each(vctTemp.begin(), vctTemp.end(), [=, &b](int v){ cout << v+a << endl; b++; }); cout << b << endl; }
int temp = 10;
vector<int> ivec = {30, -10, -20, 50, 40 ,100, -50};
std::sort(ivec.begin(), ivec.end(), [](const int &x, const int &y) {return abs(x) < abs(y);});
std::for_each(ivec.begin(), ivec.end(), [&](int &x) { x += temp; cout << x << endl;});
三、注意事項(xiàng):
比較上面三種方式,有一些細(xì)節(jié)需要注意:
1. closure的狀態(tài)特指其運(yùn)行的上下文。 closure將存貯它運(yùn)行時(shí)需要的上下文,從而保證在closure創(chuàng)建時(shí)的上下文可以在closure運(yùn)行時(shí)依然有效。
比如round就是closure的上下文。保存上下文的這一特點(diǎn)通常被稱作“capture”或者是"bind"。 capture可以自己寫(xiě),比如MyFuctor f(round); 也可以用boost::bind。
當(dāng)然最方便的還是讓編譯器幫你自動(dòng)完成。編譯器將自動(dòng)識(shí)別closure用到的變量,然后創(chuàng)建一個(gè)匿名的類,將這個(gè)變量保存到匿名類的成員變量中。
C++中有兩種capture方式,by value和by reference。寫(xiě)法是[=]和[&]。
需要注意的是,capture by reference是不會(huì)修改被capture變量的生命周期的,你要保證被capture的變量在closure運(yùn)行時(shí)是有效的。
這一點(diǎn)不像Java,Java中變量被capture的話,就變成被引用了,從而GC不會(huì)回收它。
2. closure的類型是隱藏的,每次創(chuàng)建一個(gè)closure,編譯器都會(huì)創(chuàng)建一個(gè)新的類型。
如果你想保存一個(gè)clousre時(shí)就不是那么直接,因?yàn)槟悴恢浪念愋汀_@時(shí)那需要一些模板技巧,可參考boost::function的實(shí)現(xiàn)。
簡(jiǎn)單的方式是直接用std::function來(lái)保存。
std::function<int(float)> closure;
closure = [](float f) { return 0.0f };
closure = [](float f) { return 1.0f };
四、閉包(匿名函數(shù))用處,可以是流程更清晰,易于理解,一般不能單獨(dú)使用,必須有上下文,閉包里處理的是上下文中的一些變量。一般情況下不能單獨(dú)使用
auto Do=[&]()
{
}
auto nextDo=[=](){
}