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

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