C++11的Lambda表達式是什么
Lambda表達式稱為匿名函數,所謂匿名函數,有以下兩方面的含義
- Lambda表達式是函數的一種,從功能上看,Lambda表達式和函數的作用完全一樣(雖然Lambda表達式實質是一個類),使用Lambda表達式完成的功能,也可以使用普通函數來完成;
- Lambda表達式是匿名的,即沒有名字,而普通函數必須有函數名;其實,Lambda表達式也是可以命名的,然后通過名字來調用Lambda表達式,所以,Lambda表達式可以匿名,但不是必須匿名。
既然功能和普通函數一樣,那么C++11為什么還要引入Lambda表達式呢?相比普通函數,Lambda表達式有以下優點
-
Lambda可以就地定義,比函數更方便,比如,我們可以直接在函數內部定義Lambda表達式
1
2
3
4
5void fun(){
auto add = \[\] (int x, int y) { return x + y; };// 定義Lambda表達式
int a = add(1,2);
int b = add(a,3);
} -
Lambda表達式的作用域更容易控制,有助於減少命名沖突
上述實例中,add的作用域僅限於fun函數內部,如果我們定義add為普通函數,那么add就是全局函數了,可能和其他函數名沖突。 -
Lambda表達式可以自動捕獲上下文中的變量,比普通函數更方便
1
2
3
4
5void fun(){
int y=1;
auto add = \[=\] (int x) { return x + y; };// Lambda中可以直接使用外部變量y
int a = add(1);
}上述代碼中,變量y屬於add外定義的變量,但是add依舊可以直接使用變量y,而普通函數做不到這個功能,普通函數要想使用變量y,則需要通過參數傳遞把y傳遞過去,多麻煩啊?下文會更詳細的說明捕獲變量的用法。
-
Lambda通常會結合function使用(請閱讀《c++11 function、bind用法詳解》),再加上自動捕獲變量,可以完成很多功能,威力無窮。
Lambda表達式的語法詳解
按照上圖中的標號,具體解釋如下:
標號1:指定捕獲列表,所謂捕獲,是把Lambda表達式之外定義的變量,捕獲到Lambda表達式內部,這樣Lambda內部可以直接引用這些變量,省去參數傳遞的過程。
捕獲分為兩種方式:
- 按值捕獲,捕獲到Lambda表達式內部的變量是副本,注意,按值捕獲的變量默認是不能修改的,可以使用mutable關鍵字突破這個限制,見下文標號3.
- 按引用捕獲,捕獲到Lambda表達式內部的變量是引用,修改變量會影響外部的同名變量
捕獲的舉例如下:
- [],空捕獲列表,不捕獲任何變量,此時引用外部變量則會提示編譯錯誤
- [=],默認按值捕獲全部變量
- [&],默認按引用捕獲全部變量
- [=,&x,&y],默認按值捕獲全部變量,但是變量x,變量y按引用捕獲
- [&,=x,=y],默認按引用捕獲全部變量,但是變量x,變量y按值捕獲
- [&,x,y],效果同上,即變量名前面沒有寫=或者&時,默認為按值捕獲
- [=,x,y],編譯出錯,變量x,變量y按值捕獲,和默認按值捕獲全部變量重復
- [x,y],只按值捕獲變量x和變量y
- [&x,&y],只按引用捕獲變量x和變量y
- [x,&y],只按值捕獲變量x,按引用捕獲變量y
- [=x,=y],編譯出錯,應為[x,y]
- [this],捕獲this指針,然后在Lambda表達式內部就可以直接引用類成員了
標號2:函數參數
用法和普通函數一樣
1 |
auto add = \[\] (int x, int y) { return x + y; }; |
add有兩個參數,將來調用add時請傳遞兩個int變量
標號3:mutable,用來突破不能修改按值捕獲變量的限制
如下代碼,按值捕獲了變量x,在Lambda表達式內部,是不能修改x的值的
1 |
int x = 1; |
為了突破上面的限制,添加mutable即可編譯成功
1 |
int x = 1; |
注意,即使Lambda表達式內部修改了x的值,但是依舊不影響Lambda表達式外部的x的值,兩者是相互獨立的。
標號4:throw關鍵字,和C++中throw用法保持一致
標號5:Lambda表達式返回值的類型
標號6:函數內容;注意函數最后面,需要添加一個;分號
Lambda表達式的使用示例,請參考《c++11 function、bind用法詳解》
Lambda表達式的實質
Lambda實質是類,通過下面的例子可以很多認識到Lambda表達式和普通函數的不同
1 |
int x = 1; |
上述代碼中,第二次調用f是,f內部的變量x保留了上次的值。其實,Lambda實質是類,而f是類的實例,x是f的成員變量,多次調用f,調用的是同一個實例,這是和普通函數本質不同的地方。