C++11 Lambda表达式(匿名函数)详解
使用 STL 时,往往会大量用到函数对象,为此要编写很多函数对象类。有的函数对象类只用来定义了一个对象,而且这个对象也只使用了一次,编写这样的函数对象类就有点浪费。
而且,定义函数对象类的地方和使用函数对象的地方可能相隔较远,看到函数对象,想要查看其 operator() 成员函数到底是做什么的也会比较麻烦。
对于只使用一次的函数对象类,能否直接在使用它的地方定义呢?Lambda 表达式能够解决这个问题。使用 Lambda 表达式可以减少程序中函数对象类的数量,使得程序更加优雅。
Lambda 表达式的定义形式如下:
下面是一个合法的Lambda表达式:
11 2 33 4
程序第 2 行使得数组 a 按个位数从小到大排序。具体的原理是:sort 在执行过程中,需要判断两个元素 x、y 的大小时,会以 x、y 作为参数,调用 Lambda 表达式所代表的函数,并根据返回值来判断 x、y 的大小。这样,就不用专门编写一个函数对象类了。
第 3 行,for_each 的第 3 个参数是一个 Lambda 表达式。for_each 执行过程中会依次以每个元素作为参数调用它,因此每个元素都被输出。
下面是用到了外部变量的Lambda表达式的程序:
10
2 4 6 8
第 8 行,
实际上,“外部变量访问方式说明符”还可以有更加复杂和灵活的用法。例如:
例如下面的程序:
100
225
201, 301
第 6 行定义了一个变量 ff,ff 的类型是 auto,表示由编译器自动判断其类型(这也是 C++11 的新特性)。本行将一个 Lambda 表达式赋值给 ff,以后就可以通过 ff 来调用该 Lambda 表达式了。
第 11 行通过 ff,以 15 作为参数 n 调用上面的 Lambda 表达式。该 Lambda 表达式指明,对于外部变量 y、z,可以修改其值;对于其他外部变量,例如 x,不能修改其值。因此在该表达式执行时,可以修改外部变量 y、z 的值,但如果出现试图修改 x 值的语句,就会编译出错。
而且,定义函数对象类的地方和使用函数对象的地方可能相隔较远,看到函数对象,想要查看其 operator() 成员函数到底是做什么的也会比较麻烦。
对于只使用一次的函数对象类,能否直接在使用它的地方定义呢?Lambda 表达式能够解决这个问题。使用 Lambda 表达式可以减少程序中函数对象类的数量,使得程序更加优雅。
Lambda 表达式的定义形式如下:
[外部变量访问方式说明符] (参数表) -> 返回值类型
{
语句块
}
=
或&
,表示{}
中用到的、定义在{}
外面的变量在{}
中是否允许被改变。=
表示不允许,&
表示允许。当然,在{}
中也可以不使用定义在外面的变量。“-> 返回值类型”可以省略。下面是一个合法的Lambda表达式:
[=] (int x, int y) -> bool {return x%10 < y%10; }
Lambda 表达式实际上是一个函数,只是它没有名字。下面的程序段使用了上面的 Lambda 表达式:int a[4] = {11, 2, 33, 4}; sort(a, a+4, [=](int x, int y) -> bool { return x%10 < y%10; } ); for_each(a, a+4, [=](int x) { cout << x << " ";} );这段程的输出结果是:
11 2 33 4
程序第 2 行使得数组 a 按个位数从小到大排序。具体的原理是:sort 在执行过程中,需要判断两个元素 x、y 的大小时,会以 x、y 作为参数,调用 Lambda 表达式所代表的函数,并根据返回值来判断 x、y 的大小。这样,就不用专门编写一个函数对象类了。
第 3 行,for_each 的第 3 个参数是一个 Lambda 表达式。for_each 执行过程中会依次以每个元素作为参数调用它,因此每个元素都被输出。
下面是用到了外部变量的Lambda表达式的程序:
#include <iostream> #include <algorithm> using namespace std; int main() { int a[4] = { 1, 2, 3, 4 }; int total = 0; for_each(a, a + 4, [&](int & x) { total += x; x *= 2; }); cout << total << endl; //输出 10 for_each(a, a + 4, [=](int x) { cout << x << " "; }); return 0; }程序的输出结果如下:
10
2 4 6 8
第 8 行,
[&]
表示该 Lambda 表达式中用到的外部变量 total 是传引用的,其值可以在表达式执行过程中被改变(如果使用[=]
,编译无法通过)。该 Lambda 表达式每次被 for_each 执行时,都将 a 中的一个元素累加到 total 上,然后将该元素加倍。实际上,“外部变量访问方式说明符”还可以有更加复杂和灵活的用法。例如:
-
[=, &x, &y]
表示外部变量 x、y 的值可以被修改,其余外部变量不能被修改; -
[&, x, y]
表示除 x、y 以外的外部变量,值都可以被修改。
例如下面的程序:
#include <iostream> using namespace std; int main() { int x = 100,y=200,z=300; auto ff = [=,&y,&z](int n) { cout <<x << endl; y++; z++; return n*n; }; cout << ff(15) << endl; cout << y << "," << z << endl; }程序的输出结果如下:
100
225
201, 301
第 6 行定义了一个变量 ff,ff 的类型是 auto,表示由编译器自动判断其类型(这也是 C++11 的新特性)。本行将一个 Lambda 表达式赋值给 ff,以后就可以通过 ff 来调用该 Lambda 表达式了。
第 11 行通过 ff,以 15 作为参数 n 调用上面的 Lambda 表达式。该 Lambda 表达式指明,对于外部变量 y、z,可以修改其值;对于其他外部变量,例如 x,不能修改其值。因此在该表达式执行时,可以修改外部变量 y、z 的值,但如果出现试图修改 x 值的语句,就会编译出错。
所有教程
- C语言入门
- C语言编译器
- C语言项目案例
- 数据结构
- C++
- STL
- C++11
- socket
- GCC
- GDB
- Makefile
- OpenCV
- Qt教程
- Unity 3D
- UE4
- 游戏引擎
- Python
- Python并发编程
- TensorFlow
- Django
- NumPy
- Linux
- Shell
- Java教程
- 设计模式
- Java Swing
- Servlet
- JSP教程
- Struts2
- Maven
- Spring
- Spring MVC
- Spring Boot
- Spring Cloud
- Hibernate
- Mybatis
- MySQL教程
- MySQL函数
- NoSQL
- Redis
- MongoDB
- HBase
- Go语言
- C#
- MATLAB
- JavaScript
- Bootstrap
- HTML
- CSS教程
- PHP
- 汇编语言
- TCP/IP
- vi命令
- Android教程
- 区块链
- Docker
- 大数据
- 云计算