C++11--匿名函數(Lambda函數)

一、定義

lambda是一種匿名函數,即沒有函數名的函數。lambda函數的語法定義爲:

[捕捉列表] (參數) mutable -> 返回值類型 {函數體}

二、[捕捉列表],定義能夠捕獲的函數外的變量,通俗地說捕獲就是匿名函數外所在作用域內的變量,這些變量可以在函數體內部調用。捕獲有兩種形式,按值捕獲和按引用捕獲。按值捕獲的變量相當於和函數外作用域內同名的一個變量,在函數內對改變量的修改不會影響函數外變量。按引用捕獲就是直接引用函數外作用域內的變量,在函數內對改變量的修改就是對函數外變量的修改。

[var] 表示以值傳遞方式捕捉變量var

[=] 表示值傳遞捕捉所有父作用域變量

[&var] 表示以引用傳遞方式捕捉變量var

[&] 表示引用傳遞捕捉所有父作用域變量

[this] 表示值傳遞方式捕捉當前的this指針

[=,&a] 表示以引用傳遞方式捕捉a,值傳遞方式捕捉其他變量

[=a,&] 表示以值傳遞方式捕捉a,引用傳遞方式捕捉其他變量

示例:

int main(int argc, char* argv[])
{
    int a = 5, b = 7;
    auto total = [](int x, int y)->int {return x + y; };    //接受兩個參數
    cout << total(a, b)<<endl;  //12
    auto fun1 = [=] {return a + b; };   //值傳遞捕捉父作用域變量
    cout << fun1() << endl; //12
    auto fun2 = [&](int c) {b = a + c; a = 1; };    //省略了返回值類型,引用捕獲所有
    fun2(3);    //1 8
    cout << a <<" "<< b << endl;
    a = 5; b = 7;   //被修改後,重新賦值
    auto fun3 = [=, &b](int c) mutable {b = a + c; a = 1; };    //以值傳遞捕捉的變量,在函數體裏如果要修改,要加mutaple,因爲默認const修飾
    fun3(3);
    cout << a << " " <<b<< endl;    //5,8
    a = 5; b = 7;   //被修改後,重新賦值
    auto fun4 = [=](int x, int y) mutable->int {a += x; b += y; return a + b; };
    int t = fun4(10, 20);
    cout << t << endl;  //42
    cout << a <<" "<< b << endl;    //5 7
    return 0;
}

三、mutable

匿名函數默認是const屬性,值傳遞的變量在函數體內不能被修改(引用傳遞的變量可以修改)。如果需要在函數體內去修改值傳遞的變量,則需要添加mutable關鍵字。當lambda中使用了mutable修飾符,則“參數列表”是不可以省略掉的,即使參數爲空。

四、返回值類型

函數體中所有return返回的都是同一類型的話,編譯器會自行判斷函數的返回類型,“-> 返回值類型”可以省略。

五、lambda和static inline函數

Lambda函數可以省略外部聲明的static inline函數,其相當於一個局部函數。局部函數僅屬於父作用域,比起外部的static inline函數,或者是自定義的宏,Lambda函數並沒有實際運行時的性能優勢(但也不會差),但是Lambda函數可讀性更好。父函數結束後,該Lambda函數就不再可用了,不會污染任何名字空間。

六、lambda函數與函數指針

Lambda函數並不是簡單的函數指針類型,或者自定義類型;每個Lambda函數會產生一個閉包類型的臨時對象(右值)。但是C++11允許Lambda函數向函數指針的轉換,前提是:

(1)Lambda沒有捕捉任何變量

(2)函數指針所示的函數原型,必須和Lambda有相同的調用方式

示例:

int main(int argc, char* argv[])
{
    int a = 3, b = 4;
 
    auto total = [](int x, int y)->int {return x + y; };
    typedef int(*all)(int x, int y);
    typedef int(*one)(int x);
 
    all p;
    p = total;
    one q;
    q = total;  //報錯,參數不一致
 
    decltype(total) all_1 = total;
    decltype(total) all_2 = p;  //報錯,指針無法轉換爲Lambda
 
    return 0;
}

七、lambda與STL

從C++11開始,Lambda被廣泛用在STL中,比如foreach。與函數指針比起來,函數指針有巨大的缺陷:1.函數定義在別處,閱讀起來很困難;2.使用函數指針,很可能導致編譯器不對其進行inline優化,循環次數太多時,函數指針和Lambda比起來性能差距太大。函數2指針不能應用在一些運行時才能決定的狀態,在沒有C++11時,只能用仿函數。使得學習STL算法的代價大大降低。

但是Lambda並不是仿函數的完全代替者。由Lambda的捕捉列表的限制造成的,僅能捕捉副作用域的變量。放函數具有天生跨作用域共享的特徵。

參考:

https://www.cnblogs.com/WindSun/p/11182276.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章