C++11中的Lambda 表達式用於定義並創建匿名的函數對象,以簡化編程工作。
Lambda簡介
Lambda表達式一般都是從方括號[]開始,然後結束於花括號{},主要包括五個部分:
- [捕獲列表 capture]:對外部變量的捕獲方式說明,是必須的;
- (操作符重載函數參數 params):沒有參數及修飾時可省略,是可選的;
- mutable 或 exception(指定Lambda表達式可以拋出的異常)聲明:是可選的;
- -> 返回值類型:返回值爲void,或函數體只有一處return(自動推斷返回類型)可省略;
- {函數體 body}:表達式實現部分,是必須的;
常見幾種Lambda表達式形式:
表達式 | |
---|---|
[ capture ] ( params ) mutable exception attribute -> ret { body } |
(1) |
[ capture ] ( params ) -> ret { body } |
(2) |
[ capture ] ( params ) { body } |
(3) |
[ capture ] { body } |
(4) |
- (1)是完整的Lambda表達式;
- (2)常見的Lambda表達式;
- (3)省略返回值的Lambda表達式:若有return語句,則據其推斷返回類型;否則爲無返回類型函數(
void f(…){}
); - (4)省略參數列表,生成無參數函數(
f(){}
);
如在sort函數中應用Lambda表達式:
std::sort(x, x + N,
// Lambda expression begins
[](float a, float b) {
return std::abs(a) < std::abs(b);
});
Capture列表
對於Lambda表達式,編譯器會自動生成一個匿名類(重載()運算符
),稱爲閉包類型(closure type);在運行時,就返回這個匿名閉包類型的實例。閉包的一個強大之處是其可以通過傳值或者引用的方式捕獲其當前作用域內的變量,前面方括號就是用來定義捕獲模式以及變量的,因此又將其稱爲Lambda捕獲塊。
Capture
是傳遞給閉包函數對象類的構造函數的:只能是那些Lambda表達式所在作用範圍內可見的局部變量及其所在類的this指針。
- [=] 以值的方式捕獲所有的可見的局部變量(包括Lambda所在類的 this)。
- [&] 以引用的方式捕獲所有的外可見的局部變量(包括Lambda所在類的 this)。
- [a,&b] a變量以值的方式被捕獲,b以引用的方式被捕獲。
- [=, &foo] 以引用的方式捕獲foo,以值方式捕獲所有其他外部變量。
- [&, foo] 以值的方式捕獲foo,以引用方式捕獲所有其他外部變量。
- [this] 通過引用捕獲當前對象(類的this指針)。
- [*this] 通過傳值方式捕獲當前對象;
注意:Capture並不能延長其捕獲變量的生命週期,因此只捕獲真正所需的變量,且避免懸掛引用的出現(在調用Lambda表達式時,引用變量因超出其聲明域,而變的無效)。
mutable說明
默認情況下,使用值方式捕獲的變量是不允許改變的(類似const成員變量),在閉包對象內永遠保存的是其最初捕獲時的值。若要對捕獲的值進行修改,則需要使用mutable修飾,修飾後:
- 修改會累積:相當於修改類實例的成員變量;
- 修改不影響被捕獲的外部變量的值;
如下所示:每次調用fun時都會累加fun對象內部的Count,但是外部的nCount一直保持原來的值(10)。
int nCount = 10;
auto fun = [nCount]()mutable {
++nCount;
cout << "In: " << nCount << endl;
};
fun();
fun();
cout << "Out: " << nCount << endl;
// In: 11
// In: 12
// Out: 10