C++11的Lambda表达式是什么

Lambda表达式称为匿名函数,所谓匿名函数,有以下两方面的含义

  • Lambda表达式是函数的一种,从功能上看,Lambda表达式和函数的作用完全一样(虽然Lambda表达式实质是一个类),使用Lambda表达式完成的功能,也可以使用普通函数来完成;
  • Lambda表达式是匿名的,即没有名字,而普通函数必须有函数名;其实,Lambda表达式也是可以命名的,然后通过名字来调用Lambda表达式,所以,Lambda表达式可以匿名,但不是必须匿名。

既然功能和普通函数一样,那么C++11为什么还要引入Lambda表达式呢?相比普通函数,Lambda表达式有以下优点

  • Lambda可以就地定义,比函数更方便,比如,我们可以直接在函数内部定义Lambda表达式

    1
    2
    3
    4
    5
    void fun(){
        auto add = \[\] (int x, int y) { return x + y; };// 定义Lambda表达式
        int a = add(1,2);
        int b = add(a,3);
    }
  • Lambda表达式的作用域更容易控制,有助于减少命名冲突
    上述实例中,add的作用域仅限于fun函数内部,如果我们定义add为普通函数,那么add就是全局函数了,可能和其他函数名冲突。

  • Lambda表达式可以自动捕获上下文中的变量,比普通函数更方便

    1
    2
    3
    4
    5
    void fun(){
        int y=1;
        auto add = \[=\] (int x) { return x + y; };// Lambda中可以直接使用外部变量y
        int a = add(1);
    }

    上述代码中,变量y属于add外定义的变量,但是add依旧可以直接使用变量y,而普通函数做不到这个功能,普通函数要想使用变量y,则需要通过参数传递把y传递过去,多麻烦啊?下文会更详细的说明捕获变量的用法。

  • Lambda通常会结合function使用(请阅读《c++11 function、bind用法详解》),再加上自动捕获变量,可以完成很多功能,威力无穷。

Lambda表达式的语法详解

lamdba.jpg

按照上图中的标号,具体解释如下:

标号1:指定捕获列表,所谓捕获,是把Lambda表达式之外定义的变量,捕获到Lambda表达式内部,这样Lambda内部可以直接引用这些变量,省去参数传递的过程。

捕获分为两种方式:

  • 按值捕获,捕获到Lambda表达式内部的变量是副本,注意,按值捕获的变量默认是不能修改的,可以使用mutable关键字突破这个限制,见下文标号3.
  • 按引用捕获,捕获到Lambda表达式内部的变量是引用,修改变量会影响外部的同名变量

捕获的举例如下:

  • [],空捕获列表,不捕获任何变量,此时引用外部变量则会提示编译错误
  • [=],默认按值捕获全部变量
  • [&],默认按引用捕获全部变量
  • [=,&x,&y],默认按值捕获全部变量,但是变量x,变量y按引用捕获
  • [&,=x,=y],默认按引用捕获全部变量,但是变量x,变量y按值捕获
  • [&,x,y],效果同上,即变量名前面没有写=或者&时,默认为按值捕获
  • [=,x,y],编译出错,变量x,变量y按值捕获,和默认按值捕获全部变量重复
  • [x,y],只按值捕获变量x和变量y
  • [&x,&y],只按引用捕获变量x和变量y
  • [x,&y],只按值捕获变量x,按引用捕获变量y
  • [=x,=y],编译出错,应为[x,y]
  • [this],捕获this指针,然后在Lambda表达式内部就可以直接引用类成员了

标号2:函数参数

用法和普通函数一样

1
auto add = \[\] (int x, int y) { return x + y; };

add有两个参数,将来调用add时请传递两个int变量

标号3:mutable,用来突破不能修改按值捕获变量的限制

如下代码,按值捕获了变量x,在Lambda表达式内部,是不能修改x的值的

1
2
3
int x = 1;
auto f=\[x\](){x++;};// 编译错误,不能修改x的值
f();

为了突破上面的限制,添加mutable即可编译成功

1
2
3
int x = 1;
auto f=\[x\]()mutable{x++;};// 编译成功
f();

注意,即使Lambda表达式内部修改了x的值,但是依旧不影响Lambda表达式外部的x的值,两者是相互独立的。

标号4:throw关键字,和C++中throw用法保持一致

标号5:Lambda表达式返回值的类型

标号6:函数内容;注意函数最后面,需要添加一个;分号

Lambda表达式的使用示例,请参考《c++11 function、bind用法详解》

Lambda表达式的实质

Lambda实质是类,通过下面的例子可以很多认识到Lambda表达式和普通函数的不同

1
2
3
4
5
6
7
8
9
int x = 1;
auto f=\[x\]()mutable{
x++;
cout<<x<<endl;};
f();
f();
//输出结果
2
3

上述代码中,第二次调用f是,f内部的变量x保留了上次的值。其实,Lambda实质是类,而f是类的实例,x是f的成员变量,多次调用f,调用的是同一个实例,这是和普通函数本质不同的地方。

C++11 Lambda表达式(匿名函数)用法详解的更多相关文章

  1. [二] java8 函数式接口详解 函数接口详解 lambda表达式 匿名函数 方法引用使用含义 函数式接口实例 如何定义函数式接口

    函数式接口详细定义 package java.lang; import java.lang.annotation.*; /** * An informative annotation type use ...

  2. java8函数式接口详解、函数接口详解、lambda表达式匿名函数、方法引用使用含义、函数式接口实例、如何定义函数式接口

    函数式接口详细定义 函数式接口只有一个抽象方法 由于default方法有一个实现,所以他们不是抽象的. 如果一个接口定义了一个抽象方法,而他恰好覆盖了Object的public方法,仍旧不算做接口的抽 ...

  3. SQL中CONVERT()函数用法详解

    SQL中CONVERT函数格式: CONVERT(data_type,expression[,style]) 参数说明: expression 是任何有效的 Microsoft® SQL Server ...

  4. C语言对文件的操作函数用法详解2

    fopen(打开文件) 相关函数 open,fclose 表头文件 #include<stdio.h> 定义函数 FILE * fopen(const char * path,const  ...

  5. C语言对文件的操作函数用法详解1

    在ANSIC中,对文件的操作分为两种方式,即: 流式文件操作 I/O文件操作 一.流式文件操作 这种方式的文件操作有一个重要的结构FILE,FILE在stdio.h中定义如下: typedef str ...

  6. php中setcookie函数用法详解(转)

    php中setcookie函数用法详解:        php手册中对setcookie函数讲解的不是很清楚,下面是我做的一些整理,欢迎提出意见.        语法:        bool set ...

  7. eval()函数用法详解

    eval()函数用法详解:此函数可能使用的频率并不是太高,但是在某些情况下具有很大的作用,下面就介绍一下eval()函数的用法.语法结构: eval(str) 此函数可以接受一个字符串str作为参数, ...

  8. 转载 LayoutInflater的inflate函数用法详解

    http://www.open-open.com/lib/view/open1328837587484.html LayoutInflater的inflate函数用法详解 LayoutInflater ...

  9. delphi中Application.MessageBox函数用法详解

    delphi中Application.MessageBox函数用法详解 Application.MessageBox是TApplication的成员函数,声明如下:functionTApplicati ...

  10. Python:lambda表达式(匿名函数)

    lambda表达式: 通常是在需要一个函数,但是又不想费神去命名一个函数的场合下使用,也就是指匿名函数. 当我们在传入函数时,有些时候,不需要显式地定义函数,直接传入匿名函数更方便. 在Python中 ...

随机推荐

  1. 【一步步开发AI运动APP】十、微调优化内置运动分析器,灵活适配不同的应用场景

    之前我们为您分享了[一步步开发AI运动小程序]开发系列博文,通过该系列博文,很多开发者开发出了很多精美的AI健身.线上运动赛事.AI学生体测.美体.康复锻炼等应用场景的AI运动小程序:为了帮助开发者继 ...

  2. Shell常用指令操作

    sed命令 替换目录下所有文件的某个字符串 sed -i 's/test/yuhaohao/g' `grep -lr yuhaohao *` export 函数到外部使用 functon test() ...

  3. Free Mybatis Tool插件

    Free Mybatis plugin Free Mybatis Tool 老规矩先吹一波......这个idea里面的插件真的十分nice,上个图让你们知道他的优秀.直接在idea插件搜索就可以安装 ...

  4. 未能加载文件或程序集“System.Runtime.WindowsRuntime, Version=4.0.14.0, Culture=neutral, PublicKeyToken=b77a5c561934e089”或它的某一个依赖项。不应出于执行的目的加载引用程序集。只能在仅限反射的加载程序上下文中加载引用程序集。 (异常来自 HRESULT:0x80131058)

    VS项目编译时报错: 未能加载文件或程序集"System.Runtime.WindowsRuntime, Version=4.0.14.0, Culture=neutral, PublicK ...

  5. 华为发布伙伴SDK优选库,并推动SDK安全隐私新标准制定

    6月21日,在华为开发者大会2025<鸿蒙生态伙伴SDK论坛>上,华为与中国信通院标准所.鸿蒙生态伙伴代表上海CA.一砂.三未信安,共同宣布"鸿蒙生态伙伴SDK优选库" ...

  6. 层次分析法的Python实现--数学建模学习日志

    数学建模比赛即将到来,大家应该都投身于学习当中了,b站上比较热门的一个课程是 b站数学建模学习视频 在这里讲解了数学建模常见的方法和写论文的要点,同时up主贴心地有所有方法的源码实现,但是全部都是ma ...

  7. java基础--eclipse使用、object类、String类、stringbuffer类

    eclipse使用的步骤 第一步: 选择工作目录. 以后在Eclipse上面写的所有代码都是在工作目录上的. 第二步: 在Project Exploer 窗口上创建一个工程,以后我们写代码都是以工程作 ...

  8. jre 的生成与使用

    前言 从 Java 9 开始,Oracle 不再单独提供 JRE(Java Runtime Environment) 的独立安装包,而是推荐开发者使用 模块化的 JRE 或 jlink 工具 来自定义 ...

  9. 树莓派4安装centos

    下载镜像这是用的华为的镜像源仓库中下载的,注意不要下载桌面版的centos,安装不上,直接彩虹屏.下载第三个就行http://mirrors.huaweicloud.com/centos-altarc ...

  10. ViewModelProviders报错

    //创建ViewModel实例 //MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class); //该方法已弃用 M ...