zoukankan      html  css  js  c++  java
  • C++11 Lambda表达式(匿名函数)用法详解

    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.jpglamdba.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,调用的是同一个实例,这是和普通函数本质不同的地方。

  • 相关阅读:
    移动端轮播图
    移动端的注册页面
    点击显示或者消失的效果(手风琴效果)
    canvas的一些简单绘制方法
    用canvas来手动绘画
    canvas标签的运用
    Html5新标签解释及用法
    最近的心得
    浅谈正则表达式
    P3197 [HNOI2008]越狱
  • 原文地址:https://www.cnblogs.com/chinasoft/p/15243879.html
Copyright © 2011-2022 走看看