为什么要lambda函数

匿名函数是许多编程语言都支持的概念,有函数体,没有函数名。1958年,lisp首先采用匿名函数,匿名函数最常用的是作为回调函数的值。正因为有这样的需求,c++引入了lambda 函数,你可以在你的源码中内联一个lambda函数,这就使得创建快速的,一次性的函数变得简单了。例如,你可以把lambda函数可在参数中传递给std::sort函数。

#include "stdafx.h"
#include <algorithm> //标准模板库算法库
#include <cmath> //数学库
#include <iostream>
using namespace std; //绝对值排序
void abssort(float* x, unsigned n)
{
//模板库排序函数
std::sort(x, x + n,
// Lambda 开始位置
[](float a, float b)
{
return (std::abs(a) < std::abs(b));
} // lambda表达式结束
);
} int _tmain(int argc, _TCHAR* argv[])
{
float a[] = { 2.1f, 3.5f, 4.0f, 5.2f, 3.3f };
abssort(a, );
for (auto& x : a)
{
cout << x << endl;
}
system("pause");
return ;
}

lambda函数的语法

基本形式如下:

[capture](parameters)->return-type {body}
  • []叫做捕获说明符,表示一个lambda表达式的开始。接下来是参数列表,即这个匿名的lambda函数的参数。
  • parameters,普通参数列表
  • ->return-type表示返回类型,如果没有返回类型,则可以省略这部分。这涉及到c++11的另一特性,参见自动类型推导,最后就是函数体部分。

  • capture clause(捕获)
  • lambda-parameter-declaration-list (变量列表)
  • mutable-specification (捕获的变量可否修改)
  • exception-specification (异常设定)
  • lambda-return-type-clause (返回类型)
  • compound-statement (函数体)

外部变量的捕获规则

默认情况下,即捕获字段为 [] 时,lambda表达式是不能访问任何外部变量的,即表达式的函数体内无法访问当前作用域下的变量。

如果要设定表达式能够访问外部变量,可以在 [] 内写入 & 或者 = 加上变量名,其中 & 表示按引用访问,= 表示按值访问,变量之间用逗号分隔,比如 [=factor, &total] 表示按值访问变量 factor,而按引用访问 total。

不加变量名时表示设置默认捕获字段,外部变量将按照默认字段获取,后面在书写变量名时不加符号表示按默认字段设置,比如下面三条字段都是同一含义:

[&total, factor]
[&, factor]
[=, &total]

#include <functional>
#include <iostream>
using namespace std;int _tmain(int argc, _TCHAR* argv[])
{
//lambd函数对象
auto fl = [](int x, int y){return x + y; };
cout << fl(, ) << endl; function<int(int, int)>f2 = [](int x, int y){return x + y; };
cout << f2(, ) << endl;
system("pause");
return ;
}

不能访问任何局部变量

如何传进去局部变量

int test = ;
//lambd函数对象捕获局部变量
auto fl = [test](int x, int y){return test +x + y; };
cout << fl(, ) << endl;

默认访问所有局部变量

int test = ;
//lambd函数对象捕获所有局部变量
auto fl = [=](int x, int y){return test +x + y; };
cout << fl(, ) << endl;

在C++11中这一部分被成为捕获外部变量

捕获外部变量

[captures] (params) mutable-> type{...} //lambda 表达式的完整形式

在 lambda 表达式引出操作符[ ]里的“captures”称为“捕获列表”,可以捕获表达式外部作用域的变量,在函数体内部直接使用,这是与普通函数或函数对象最大的不同(C++里的包闭必须显示指定捕获,而lua语言里的则是默认直接捕获所有外部变量。)

捕获列表里可以有多个捕获选项,以逗号分隔,使用了略微“新奇”的语法,规则如下

  • [ ]        :无捕获,函数体内不能访问任何外部变量
  • [ =]      :以值(拷贝)的方式捕获所有外部变量,函数体内可以访问,但是不能修改。
  • [ &]      :以引用的方式捕获所有外部变量,函数体内可以访问并修改(需要当心无效的引用);
  • [ var]   :以值(拷贝)的方式捕获某个外部变量,函数体可以访问但不能修改。
  • [ &var] :以引用的方式获取某个外部变量,函数体可以访问并修改
  • [ this]   :捕获this指针,可以访问类的成员变量和函数,
  • [ =,&var] :引用捕获变量var,其他外部变量使用值捕获。
  • [ &,var]:只捕获变量var,其他外部变量使用引用捕获。

下面代码示范了这些捕获列表的用法:、

int x = ,y=0;
  • auto f1 = [=](){ return x; };                       //以值方式捕获使用变量,不能修改
  • auto f2 = [&](){ return ++x; };                  //以引用方式捕获所有变量,可以修改,但要当心引用无效
  • auto f3 = [x](){ return x; };                      //以值方式捕获x,不能修改
  • auto f4 = [x,&y](){ y += x; };                    //以值方式捕获x,以引用方式捕获y,y可以修改
  • auto f5 = [&,y](){ x += y;};                      //以引用方式捕获y之外所有变量,y不能修改
  • auto f6 = [&](){ y += ++x;};                    //以引用方式捕获所有变量,可以修改
  • auto f7 = [](){ return x ;};                      //无捕获,不能使用外部变量,编译错误

值得注意的是变化的捕获发生在了lambda表达式的声明之时,如果使用值方式捕获,即使之后变量的值发生变化,lambda表达式也不会感知,仍然使用最初的值。如果想要使用外部变量的最新值就必须使用引用的捕获方式,但也需要当心变量的生命周期,防止引用失效。

刚才的lambda表达式运行结果是:

  • f1();                     //以值方式捕获,x,y不发生变化
  • f2();                    //函数内部x值为0,之后变为1,y没有被修改,值仍然是0;
  • f3();                    //函数内部x值仍然为0,即f3()==0;
  • f4();                    //x,y均是0,运算后y仍然是0;
  • f5();                    //y是0;引用捕获的x是1,运算后x仍然为1;
  • f6();                   //x,y均引用捕获,运算后x,y均是2

C++ lambda表达式 (一)的更多相关文章

  1. 你知道C#中的Lambda表达式的演化过程吗?

    那得从很久很久以前说起了,记得那个时候... 懵懂的记得从前有个叫委托的东西是那么的高深难懂. 委托的使用 例一: 什么是委托? 个人理解:用来传递方法的类型.(用来传递数字的类型有int.float ...

  2. Linq表达式、Lambda表达式你更喜欢哪个?

    什么是Linq表达式?什么是Lambda表达式? 如图: 由此可见Linq表达式和Lambda表达式并没有什么可比性. 那与Lambda表达式相关的整条语句称作什么呢?在微软并没有给出官方的命名,在& ...

  3. 背后的故事之 - 快乐的Lambda表达式(一)

    快乐的Lambda表达式(二) 自从Lambda随.NET Framework3.5出现在.NET开发者眼前以来,它已经给我们带来了太多的欣喜.它优雅,对开发者更友好,能提高开发效率,天啊!它还有可能 ...

  4. Kotlin的Lambda表达式以及它们怎样简化Android开发(KAD 07)

    作者:Antonio Leiva 时间:Jan 5, 2017 原文链接:https://antonioleiva.com/lambdas-kotlin/ 由于Lambda表达式允许更简单的方式建模式 ...

  5. java8中lambda表达式的应用,以及一些泛型相关

    语法部分就不写了,我们直接抛出一个实际问题,看看java8的这些新特性究竟能给我们带来哪些便利 顺带用到一些泛型编程,一切都是为了简化代码 场景: 一个数据类,用于记录职工信息 public clas ...

  6. 背后的故事之 - 快乐的Lambda表达式(二)

    快乐的Lambda表达式 上一篇 背后的故事之 - 快乐的Lambda表达式(一)我们由浅入深的分析了一下Lambda表达式.知道了它和委托以及普通方法的区别,并且通过测试对比他们之间的性能,然后我们 ...

  7. CRL快速开发框架系列教程二(基于Lambda表达式查询)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  8. Lambda 表达式递归用法实例

    注意: 使用Lambda表达式会增加额外开销,但却有时候又蛮方便的. Windows下查找子孙窗口实例: HWND FindDescendantWindows(HWND hWndParent, LPC ...

  9. Spark中Lambda表达式的变量作用域

    通常,我们希望能够在lambda表达式的闭合方法或类中访问其他的变量,例如: package java8test; public class T1 { public static void main( ...

  10. 释放Android的函数式能量(I):Kotlin语言的Lambda表达式

    原文标题:Unleash functional power on Android (I): Kotlin lambdas 原文链接:http://antonioleiva.com/operator-o ...

随机推荐

  1. 转:移动建站工具(一):分秒钟将Web网站移动化

      作者唐小引 移动建站工具Web移动化简易开发MobifyTOPMobile Joomla!MoFuseWordPress优化 摘要:时下移动端显然已是诸多企业都想要占领的重要阵地.但限于较小的屏幕 ...

  2. spring data redis jackson 配置,工具类

    spring data redis 序列化有jdk .jackson.string 等几种类型,自带的jackson不熟悉怎么使用,于是用string类型序列化,把对象先用工具类转成string,代码 ...

  3. 有关Java基础的一些笔试题总结

    针对近期腾讯.京东.网易等公司的笔试.遇到一些有关Java基础的问题,在此总结.希望能通过这几道经典问题题发散,举一反三.借此打牢基础! 自己总结,望提出宝贵意见! 一.关于null的一道小题 先开开 ...

  4. CMD应用 qtp/winshell/cmd的交互

    =================================================================== '採用windows.shell的 sendkeys 方式: s ...

  5. Python: PS 图像调整--颜色梯度

    本文用 Python 实现 PS 中的色彩图,可以看到颜色的各种渐变,具体的效果可以参考以前的博客: http://blog.csdn.net/matrix_space/article/details ...

  6. Python json数据中文输出问题。

    这个问题困扰了我好久好久,最后看了一眼官方文档,解决问题了. 问题描述:从web上获取的json数据,然后对应的保存到了python的类型中.再次输出这个数据时,中文总会变成\u1234这种形式. P ...

  7. CheckException和RuntimeException

    java文档中对RuntimeException的定义是: RuntimeException 是那些可能在 Java 虚拟机正常运行期间抛出的异常的超类. 可能在执行方法期间抛出但未被捕获的 Runt ...

  8. vue.js技巧小计

    //删除数组索引方法01 del (index) { this.arr.splice(index ,1); } //删除数组索引方法01 del (index) { this.$delete(this ...

  9. SSD-tensorflow-1 demo

    一.简易识别 用最简单的已训练好的模型对20类目标做检测. 你电脑的tensorflow + CUDA + CUDNN环境都是OK的, 同时python需要安装cv2库 {      'aeropla ...

  10. 2017国家集训队作业[agc016b]Color Hats

    2017国家集训队作业[agc016b]Color Hats 题意: 有\(N\)个人,每个人有一顶帽子.帽子有不同的颜色.现在,每个人都告诉你,他看到的所有其它人的帽子共有多少种颜色,问有没有符合所 ...