C++在C11标准中引入了匿名函数,即没有名字的临时函数,又称之为lambda表达式.lambda表达式 实质上是创建一个匿名函数/对象。即你可以理解为(Lambda 表达式实际上是一个函数,只是它没有名字。)

为什么要使用它呢?

因为使用 STL 时,往往会大量用到函数对象,为此要编写很多函数对象类。有的函数对象类只用来定义了一个对象,而且这个对象也只使用了一次,编写这样的函数对象类就有点浪费。而且,定义函数对象类的地方和使用函数对象的地方可能相隔较远,看到函数对象,想要查看其 operator() 成员函数到底是做什么的也会比较麻烦。

因此对于只使用一次的函数对象类,能否直接在使用它的地方定义呢?Lambda 表达式能够解决这个问题。使用 Lambda 表达式可以减少程序中函数对象类的数量,使得程序更加优雅。

格式如下:

[caputrue](params)opt->ret{body;};
[函数对象参数] (操作符重载函数参数) mutable 或 exception 声明 -> 返回值类型 {函数体}//或者Lambda 表达式的定义形式如下:
[外部变量访问方式说明符] (参数表) -> 返回值类型
{语句块
}

"外部变量访问方式说明符"(不可省略)有如下几种格式:

(1)[]  :表示  不截取任何变量
(2)[&] :表示  截取外部作用域中所有变量,并作为引用在函数体中使用
(3)[=]  :表示 截取外部作用域中所有变量,并拷贝一份在函数体中使用
(4)[=, &foo]:表示   截取外部作用域中所有变量,并拷贝一份在函数体中使用,但是对foo变量使用引用
(5)[bar] :表示  截取bar变量并且拷贝一份在函数体重使用,同时不截取其他变量
(6)[this]:表示  截取当前类中的this指针。如果已经使用了&或者=就默认添加此选项。

常用的[=]或者[&]表示{}中用到的、定义在{}外面的变量在{}中是否允许被改变。[=]的话表示不允许被改变。[&]表示允许被改变(此处&类似于函数传参引用的形式吧?)当然,在{}中也可以不使用定义在外面的变量。“-> 返回值类型”是可以省略。

2.重载参数列表
调用的时候需要传递的参数即参数表(参数可以缺省) 下面调用的时候括号里面的2会赋值给形参x;y用默认值3。

#include <iostream>
using namespace std;
int main()
{[](int x, int y=3) {cout <<x=y<<endl;}(2);//最后的(2)传入的是参数,没传入的使用默认return 0;}//程序整个输出 是 5

3.返回类型(可以自动推导 可以省略)
auto fun = [](int x, int y)->int {cout << x + y << endl; return y;};
对于这里的->int 这个int就是返回值类型,如果有返回值类型需要在前面加上->
直接省略写成这种格式也可以[](int x,int y){cout<<x+y<<endl;return y;}
4.函数体
lambda表达式的函数体中可以和普通函数一样写,可以使用捕获的参数,写这个函数实现的具体步骤.
5.函数选项opt    (可以省略)
可以填mutable,exception,attribute

(mutable 表示函数体可以修改捕获变量的,同时可以访问捕获对象的非常属性成员函数
exception说明lambda表达式是否抛出异常以及何种异常
attribute用来声明属性)

补充说明:
按值捕获的时候,得到的是当前的值,如果想得到实时的值,建议使用引用(引用在函数体内部可以修改外部变量值)例如:

#include<iostream>
using namespace std;
int main()
{auto ptr = []() {cout << "hello" << endl; };    //lambda表达式ptr();//调用函数auto fun = [](int x, int y)->int {cout << x + y << endl; return y;};    //带参数的lambda表达式//  这里的->后面写的是返回值类型auto z=fun(3, 4);cout << z << endl;cin.get();return 0;
}

PS:对于匿名函数,一般用于传函数参数,当然也可以直接定义调用。

auto pfun=()[]{cout<<"hello world"<<endl;}//这里使用auto自动判断类型  其实是函数指针
pfun(); //调用这个函数()括号内可以传参数

(2)一般常见使用方式是在sort()函数中,作为第三个参数即自定义排序规则。如下:

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 << " ";} );

程序第 2 行使得数组 a 按个位数从小到大排序。具体的原理是:sort 在执行过程中,需要判断两个元素 x、y 的大小时,会以 x、y 作为参数,调用 Lambda 表达式所代表的函数,并根据返回值来判断 x、y 的大小。这样,就不用专门编写一个函数对象类了。
第 3 行,for_each 的第 3 个参数是一个 Lambda 表达式。for_each 执行过程中会依次以每个元素作为参数调用它,因此每个元素都被输出。

解读一下for_each()函数:

//  for_each的原型声明如下:
templateFunction for_each (InputIterator first,InputIterator last, Function fn)//输出结果11 2 33 4

可以看出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;  //输出 10for_each(a, a + 4, [=](int x) { cout << x << " "; });//输出2 4 6 8return 0;
}

第 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 = 10,y=20,z=30;auto f1  = [=,&y,&z](int n) {cout <<x << endl;//输出10y++; z++;return n*n;};cout << f1(10) << endl;//输出retur n*n即10*10=100cout << y << "," << z << endl;//输出y=y++=21,z=z++=31
}

第 6 行定义了一个变量 f1,f 1的类型是 auto,表示由编译器自动判断其类型(这也是 C++11 的新特性)。本行将一个 Lambda 表达式赋值给 f1,以后就可以通过 f1 来调用该 Lambda 表达式了。

第 11 行通过 f1,以 10 作为参数 n 调用上面的 Lambda 表达式。该 Lambda 表达式指明,对于外部变量 y、z,可以修改其值;对于其他外部变量,例如 x,不能修改其值。因此在该表达式执行时,可以修改外部变量 y、z 的值,但如果出现试图修改 x 值的语句,就会编译出错。

参考:C语言中文网站

C++11:Lambda表达式(匿名函数)理解相关推荐

  1. C++11 lambda表达式与函数对象

    C++ lambda表达式与函数对象 lambda表达式是C++11中引入的一项新技术,利用lambda表达式可以编写内嵌的匿名函数,用以替换独立函数或者函数对象,并且使代码更可读.但是从本质上来讲, ...

  2. C++11 Lambda表达式

    1.简介 1.1定义 C++11新增了很多特性,Lambda表达式(Lambda expression)就是其中之一,很多语言都提供了 Lambda 表达式,如 Python,Java ,C#等.本质 ...

  3. Java Lambda表达式的箭头理解总结

    Java Lambda表达式的箭头理解总结 文章目录 Java Lambda表达式的箭头理解总结 一.简单的Lambda的基础知识点: 二.Lambda 表达式示例 1.实现方法没有参数,无返回值的情 ...

  4. C# 3.0通过Linq、Lambda、匿名函数、代理函数实现数据查询

    这几天,正在学习Linq.Lambda,做了些实验,通过Linq.Lambda.匿名函数.代理函数4种方式实现一个简单的查询,把实现结果记录一下,以免忘记.       这段代码中有一个Person类 ...

  5. 函数递归/二分法/列表,字典生成式/三元表达式/匿名函数/内置函数

    一.递归函数 递归函数:就是在函数调用阶段直接或者间接的调用自己 递归函数的两个阶段: 1.回溯:不停的重复的一个过程,在这个过程中将问题不断的简单化,直到最终打到要求(条件) 2.递归:一次次的往回 ...

  6. 《Python数据科学指南》——1.16 使用lambda创造匿名函数

    本节书摘来自异步社区<Python数据科学指南>一书中的第1章,第1.16节,作者[印度] Gopi Subramanian ,方延风 刘丹 译,更多章节内容可以访问云栖社区"异 ...

  7. C# Lambda 和 匿名函数的GC总结

    关于Lambda和 匿名函数,闭包的GC,其实可以总结为两条. 为了方便理解,以举例说明,首先我们定义变量,静态变量,以及函数如下: static int staticVariable = 0;int ...

  8. c++11标准:匿名函数(匿名表达式)lambda

    lambda: C++11提供了对匿名函数的支持,称为Lambda函数(也叫Lambda表达式). Lambda表达式具体形式如下: 匿名函数定义/匿名表达式声明:[capture](paramete ...

  9. C++11 Lambda表达式(匿名函数)详解

    使用 STL 时,往往会大量用到函数对象,为此要编写很多函数对象类.有的函数对象类只用来定义了一个对象,而且这个对象也只使用了一次,编写这样的函数对象类就有点浪费. 而且,定义函数对象类的地方和使用函 ...

最新文章

  1. Android系统在新进程中启动自定义服务过程(startService)的原理分析 (下)
  2. java 数据库操作代码_JAVA:对数据库的一系列操作代码
  3. 虚拟机配置自定义静态ip,并能访问外网
  4. 视觉平衡与物理平衡_设计中的视觉平衡
  5. 【面试相关】python实现快速幂取余算法详解
  6. Tyvj 1176 火焰巨魔的惆怅
  7. maven打包报错找不到符号,由于找不到类中方法的解决思路
  8. Django 框架 新建app 、新建表
  9. goldendict下优质词典简介及安装
  10. 苹果无需越狱(iPhone、iPad)手机多开教程
  11. 可爱的猫咪怎么画?超详细教你如何绘画可爱的猫咪!
  12. 小盒即时通讯IM-全套开源-开箱即用
  13. ORAN C平面 Section Type 6
  14. 开源传感器网络平台OpenWSN
  15. 常见Linux命令pwd实现
  16. 【完美解决】爬虫伪装代理IP方案
  17. NDIS Filter Drivers指南
  18. 网页偶尔出现 No input file specified 提示
  19. MAC 系统安装 Maven 及环境变量配置
  20. matplotlib设置中文字体

热门文章

  1. 2021年大数据Flink(二十一):​​​​​​​案例三 会话窗口
  2. Django 验证码4.4
  3. Docker的安装和版本详细介绍
  4. Android 双屏开发 Presentation 的使用教程
  5. spring boot中的日志入门
  6. 构建自己的PHP框架--构建缓存组件(1)
  7. fastJson的使用
  8. 如何给iOS应用添加原生的二维码扫描功能
  9. Android ActionBarDrawerToggle、DrawerLayout、ActionBar 结合
  10. 3种方式理解旋转变换