C++11 Lambda表達式(匿名函數)用法詳解


C++11的Lambda表達式是什么

Lambda表達式稱為匿名函數,所謂匿名函數,有以下兩方面的含義

  • Lambda表達式是函數的一種,從功能上看,Lambda表達式和函數的作用完全一樣(雖然Lambda表達式實質是一個類),使用Lambda表達式完成的功能,也可以使用普通函數來完成;
  • Lambda表達式是匿名的,即沒有名字,而普通函數必須有函數名;其實,Lambda表達式也是可以命名的,然后通過名字來調用Lambda表達式,所以,Lambda表達式可以匿名,但不是必須匿名。

既然功能和普通函數一樣,那么C++11為什么還要引入Lambda表達式呢?相比普通函數,Lambda表達式有以下優點

  • Lambda可以就地定義,比函數更方便,比如,我們可以直接在函數內部定義Lambda表達式

    1
    2
    3
    4
    5
    void 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
    5
    void 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表達式的語法詳解

lamdba.jpglamdba.jpg

按照上圖中的標號,具體解釋如下:

標號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
2
3
int x = 1;
auto f=\[x\](){x++;};// 編譯錯誤,不能修改x的值
f();

為了突破上面的限制,添加mutable即可編譯成功

1
2
3
int x = 1;
auto f=\[x\]()mutable{x++;};// 編譯成功
f();

注意,即使Lambda表達式內部修改了x的值,但是依舊不影響Lambda表達式外部的x的值,兩者是相互獨立的。

標號4:throw關鍵字,和C++中throw用法保持一致

標號5:Lambda表達式返回值的類型

標號6:函數內容;注意函數最后面,需要添加一個;分號

Lambda表達式的使用示例,請參考《c++11 function、bind用法詳解》

Lambda表達式的實質

Lambda實質是類,通過下面的例子可以很多認識到Lambda表達式和普通函數的不同

1
2
3
4
5
6
7
8
9
int x = 1;
auto f=\[x\]()mutable{
x++;
cout<<x<<endl;};
f();
f();
//輸出結果
2
3

上述代碼中,第二次調用f是,f內部的變量x保留了上次的值。其實,Lambda實質是類,而f是類的實例,x是f的成員變量,多次調用f,調用的是同一個實例,這是和普通函數本質不同的地方。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM