Lambda的概念起源于数学中的Lambda演算(也叫λ 演算),当然,我们今天要讨论的不是数学(我也不懂J),而是编程。Lambada在程序设计中指的是‘匿名函数’。 简单来说,编程中提到的 lambda 表达式,通常是在需要一个函数,但是又不想费神去命名一个函数的场合下使用,也就是指匿名函数。 我们今天就来看看C++ 11中引入的Lambda 表达式。
引子
为了直观,我们先看一个例子:C++的标准库中有一个常用算法的库,其中提供了很多算法函数,比如 sort()。我们先来看看sort的一般使用方法:
1 | // sort algorithm example |
可以看到在使用function comparison或者object comparison的时候,我们都需要提前先定义好comparison函数。 这其实是一个(污染环境的)函数,尤其如果这个函数只会使用一次的话。
而如果使用Lambda函数会怎么样呢?
1 | // using Lambda函数 |
可以看到,这种写法实际上更易读,因为这个comparison函数具体是要做什么,非常一目了然。如果你仔细观察自己的代码,会发现这种场景其实很常见:你在某处就真的只需要一个能做一件事情的函数而已,连它叫什么名字都无关紧要。Lambda 表达式就可以用来做这件事。
利用 lambda 表达式创建那些“只用一次”或者比较短小的函数非常方便和高效。
语法
下面来看一下Lambda函数如何使用:
1 | [ capture ] ( params ) mutable exception attribute -> ret { body } (1) |
1) 完整的声明
2) 一个常lambda的声明:按副本捕获的对象不能被修改。
3) 省略后缀返回值类型:闭包的operator()的返回值类型是根据以下规则推导出的:
如果body仅包含单一的return语句,那么返回值类型是返回表达式的类型(在此隐式转换之后的类型:右值到左值、数组与指针、函数到指针)
否则,返回类型是void
4) 省略参数列表:函数没有参数,即参数列表是()
解释:
- mutable - 允许body修改传值进来的形参,以及调用它们的非常成员函数。
- exception - 提供闭包类型的operator()成员函数的异常说明或noexcept语句
- attribute - 提供闭包类型的operator()成员函数的属性说明
capture - 指定哪些在函数声明处的作用域中可见的符号将在函数体内可见。
符号表可按如下规则传入:
- [] : 不捕获任何外部变量
- [&] : 通过引用方式捕获所有外部变量
- [=] : 通过拷贝方式捕获所有外部变量
- [=, &foo] : 通过引用方式捕获 foo 变量,其他外部变量通过拷贝方式捕获
- [bar] : 通过拷贝方式捕获 bar 变量
- [this] : 捕获当前类的 this 指针
- params - 参数列表,与命名函数一样
- ret - 返回值类型。如果不存在,它由该函数的return语句来隐式决定(或者是void,例如当它不返回任何值的时候)
- body - 函数体