C++ Lambda表达式
Lambda函数也叫匿名函数,是自定义函数的一种,专指用关键字” lambda”定义的无名短函数,所以也有Lambda表达式这种说法。这种函数得名于省略了用def声明函数的标准步骤,是C++ 11中新增的特性。
一 .函数语法
我们平时调用函数的时候,都是需要被调用函数的函数名,但是匿名函数就不需要函数名,而且直接写在需要调用的地方,对于以前没用过的小伙伴来说,第一眼看见了这语法可能很迷惑。
C++11的基本语法格式:
1 | [capture](parameters) -> return_type { /* ... */ } |
(1) [capture] :[]内为外部变量的传递方式,值、引用等,如下
1 | [] //表示的是在lambda定义之前的域,对外部参数的调用; |
(2)(parameters) :()内为形参,和普通函数的形参一样。
(3)-> return_type:->后面为lambda函数的返回类型,如 -> int、-> string等。一般情况下,编译器推出lambda函数的返回值,所以这部分可以省略不写。
(4){ /* … */ }:{}内为函数主体,和普通函数一样。
修饰符
这一部分是可以省略的,常见的修饰符有两个,一个是mutable,另一个是exception
mutable:当函数参数以值引用传递方式传递时,在函数体内是不可以修改该函数参数的值的,我们可以使用mutable修饰符,使得该函数参数可以在函数体内改变,下面我们实验一下
1 | int x = 1; |
这样会报错,参数x是值传递的方式,是一个只读变量,但是我们加入mutable后,就不会报错
1 | int x = 1; |
这样我们就过了编译,不妨猜猜输出结果,是2 2还是2 1呢?
答案是2 1,注意上边加黑的字体:被mutable修饰的函数参数,该函数参数可以在函数体内改变,也就是说不会改变函数体外该变量的值,我们也可以理解为在函数体内拷贝了这个变量的同名变量。
exception:exception 声明用于指定函数抛出的异常,如抛出整数类型的异常,可以使用 throw(int)。
二. 函数应用
1、在普通函数中使用
首先是定义,执行下面这句,不会运行函数 !!!
1 | std::function<int(int,int)> addFunction= [](int a,int b) ->int { return a + b; }; |
上面代码,你知道lambda函数返回类型为int类型,但是函数左边不能直接赋值给int变量(编译器会报错),因为此处为lambda函数的定义,所以左边为函数指针类型变量,一般懒得写函数指针类型,就直接赋值给auto类型变量,如下。
1 | auto addFunction = [](int a,int b) ->int { return a + b; }; |
下面才是函数的使用、运行!!!
如何运行lambda函数并获取函数返回值?执行函数需要看下面代码:
1 | auto addFunction= [](int a,int b) ->int { return a + b; }; |
又或者如下:
1 | auto addFunction= [](int a,int b) ->int { return a + b; }; |
2、在qt信号槽绑定中使用
我觉得labmda函数非常适合在信号槽中使用。
(1)返回的函数指针可以直接用在connect函数中,刚好契合。
(2)该槽函数可能比较简单,只有这个地方使用,可以省去槽函数声明,使代码看上去更加简便,且业务代码更加集中。
基本使用
1 | connect(sys, &SYSClass::sig_1, this, [=](int index) |
绑定信号槽的时候定义lambda函数,当收到信号的时候才执行槽函数,即lambda函数。
使用示范
在mTime时间后执行动画,动画执行后delete对象,非常适合弹窗关闭时,窗口关闭的动画操作。(widgetPtr为弹窗的指针)
1 | QTimer::singleShot(mTime,widgetPtr,[=]() |
3、在函数回调中使用(std::sort排序函数为例子)
在标准库的排序函数使用中,可以使用函数回调的方式自定义排序的比较规则。
(1)sort函数提供排序算法;(2)floatList为容器变量,提供数据结构和数据;(3)他们两个之间使用迭代器连接。理解如下图:
而我们sort函数可以使用第三个参数(函数回调方式)作为比较依据进行排序,该参数就可以写成lambda函数,这样比较方法写在排序函数这里,可以使得代码更加直白、简便、集中。参考代码如下:
1 | std::sort( floatList, floatList + N, [](float a, float b) |
上面lambda函数,是sort函数中的迭代器每次运行做排序比较的时候就调用。
注意:
(1)lambda函数参数为( float , float ),类型必须与容器的元素类型一致。
(2)运行时,迭代器自动帮你把参数传入回调函数。
(3)回调函数返回值固定为bool,这里可以不写,由编译器自动确定。
三 .总结
lambda函数定义后返回的是函数指针类型,即如:std::function<int(int,int)>,所以一般很少使用,我们在很多代码中也很少看到。
正常情况下,lambda函数相对普通函数的定义和使用其实没什么优势。但是某些使用到函数指针的场合下,我们就可以酌情考虑使用,特别是函数指针作为函数参数的时候,比如qt的信号槽、回调函数等,使用起来即方便,又显得代码高大上,简直就完美O(∩_∩)O。