• C++11中新特性之:lambda 表达式


    首先摆出Lambda表达式语法

    lambda-expression:
      lambda-introducer lambda-declaratoropt compound-statement
    lambda-introducer:
      [ lambda-captureopt ]

    lambda-capture:
      capture-default
      capture-list
      capture-default , capture-list
    capture-default:
      &
      =
    capture-list:
      capture
      capture-list , capture
    capture:
      identifier
      & identifier
      this
    lambda-declarator:
      ( parameter-declaration-clause ) attribute-specifieropt mutableopt exception-specificationopt trailing-return-typeopt

    然后用一张图表示他们的属性:

    https://i-msdn.sec.s-msft.com/dynimg/IC251606.png

    1. lambda-introducer(也称为 capture 子句)

    2. lambda declarator(也称为参数列表)

    3. mutable(也称为可变规范)

    4. exception-specification(也称为异常规范)

    5. trailing-return-type(也称为返回类型)

    6. compound-statement(也称为 lambda 体)

    之后是capture 子句(最让人搞不懂的地方)

    一个 lambda 表达式实质上是一个类、构造函数和函数调用运算符。 就像你定义类时一样,在 lambda 中你必须要决定生成的对象是通过值还是引用捕获变量,或者根本不捕获。 如果一个 lambda 表达式必须访问局部变量和函数参数(但你可以访问static local variable),则必须捕获它们。 capture 子句(标准语法中的 lambda-introducer)指定 lambda 表达式的主体通过值还是引用访问封闭范围中的变量。 有与号 (&) 前缀的变量通过引用访问,没有该前缀的变量通过值访问。通过只访问局部变量是只读的。除非你加上了mutable。。

    允许空 capture 子句 [ ] 指示 lambda 表达式的主体不访问封闭范围中的变量。

    使用默认捕获模式(标准语法中的 capture-default)以通过值或引用捕获未指定的变量。 通过将 & 或 = 用作 capture 子句的第一个元素来指定默认捕获模式。 & 元素指示 lambda 表达式的主体通过引用访问未指定的变量。 = 元素指示 lambda 表达式的主体通过值访问未指定的变量。 例如,如果 lambda 体通过引用访问外部变量 total 并通过值访问外部变量 factor,则以下 capture 子句等效:

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

    关于 capture-default 的一种常见的误解是,范围内的所有变量无论是否在 lambda 中使用,都会被捕获。 事实上并非如此 - 使用 capture-default 时,只有 lambda 中提及的变量才会被捕获。

    如果 capture 子句包含 capture-default&,则该 capture 子句的 capture 中没有任何 identifier 可采用 & identifier 形式。 同样,如果 capture 子句包含 capture-default=,则该 capture 子句的 capture 不能采用 = identifier 形式。 identifier 或 this 在 capture 子句中出现的次数不能超过一次。 以下代码片段给出了一些示例。

    struct S { void f(int i); };
    
    void S::f(int i) {
        [&, i]{};    // OK
        [&, &i]{};   // ERROR: i preceded by & when & is the default
        [=, this]{}; // ERROR: this when = is the default
        [i, i]{};    // ERROR: i repeated
    }

    capture 后跟省略号是包扩展,如以下可变参数模板示例中所示:

    template<class... Args>
    void f(Args... args) {
        auto x = [args...] { return g(args...); };
        x();
    }

    在使用 capture 子句时,建议记住以下几点(尤其是使用采取多线程的 lambda 时):

    • 引用捕获可用于修改外部变量,而值捕获却不能实现此操作。 mutable 允许修改副本,而不能修改原始项。美柚mutable连副本都不能修改)

    • 引用捕获会反映外部变量的更新,而值捕获却不会反映。

    • 引用捕获引入生存期依赖项,而值捕获却没有生存期依赖项。

    参数列表

    参数列表(标准语法中的 lambda declarator)是可选的,它类似于函数的参数列表。

    由于参数列表是可选的,因此在不将参数传递到 lambda 表达式,并且其 lambda-declarator: 不包含 exception-specification、trailing-return-type 或 mutable 的情况下,可以省略空括号。(也就是后面直接接lambda体的)如

    [&]  {int a, b = 1;a = b + 1; }();

    可变规范

    通常,lambda 的函数调用运算符为 const-by-value,但对 mutable 关键字的使用可将其取消。 它不会生成可变的数据成员。 利用可变规范,lambda 表达式的主体可以修改通过值捕获的变量。 本文后面的一些示例将显示如何使用 mutable。

    异常规范

    你可以使用 throw() 异常规范来指示 lambda 表达式不会引发任何异常。 与普通函数一样,如果 lambda 表达式声明 throw() 异常规范且 lambda 体引发异常将编译错误

    返回类型

    将自动推导 lambda 表达式的返回类型。 无需表示 auto 关键字,除非指定 trailing-return-type。 trailing-return-type 类似于普通方法或函数的返回类型部分。 但是,返回类型必须跟在参数列表的后面,你必须在返回类型前面包含 trailing-return-type 关键字 ->。

    如果 lambda 体仅包含一个返回语句或其表达式不返回值,则可以省略 lambda 表达式的返回类型部分。 如果 lambda 体包含单个返回语句,编译器将从返回表达式的类型推导返回类型。 否则,编译器会将返回类型推导为 void。 下面的代码示例片段说明了这一原则。

    auto x1 = [](int i){ return i; }; // OK: return type is int
    auto x2 = []{ return{ 1, 2 }; };  // ERROR: return type is void, deducing
                                      // return type from braced-init-list is not valid
    auto x2 = [](int i) -> initializer_list<int>{return {1, 2};};  //OK: return type is compatible

    Lambda 体

    lambda 表达式的 lambda 体(标准语法中的 compound-statement)可包含普通方法或函数的主体可包含的任何内容。 普通函数和 lambda 表达式的主体均可访问以下变量类型:

    • 参数

    • 本地声明变量

    • 类数据成员(在类内部声明并且捕获 this 时)

    • 具有静态存储持续时间的任何变量(例如,全局变量)

    此外,lambda 表达式可以访问它从封闭范围中捕获的变量。 如果某个变量显示在 lambda 表达式的 capture 子句中,则该变量是显式捕获的。 否则,该变量是隐式捕获的。 lambda 表达式的主体使用默认捕获模式来访问隐式捕获的变量。

    以下示例包含通过值显式捕获变量 n 并通过引用隐式捕获变量 m 的 lambda 表达式:

  • 相关阅读:
    js 手机端触发事事件、javascript手机端/移动端触发事件
    行高引起的行内块级元素间距
    js实现复制功能
    encodeURI、encodeURIComponent、decodeURI、decodeURIComponent的区别
    CSS动画总结效果
    CSS属性之word-break:break-all强制性换行
    在handlebars.js {{#if}}条件下的逻辑运算符解决方案
    js模版引擎handlebars.js实用教程——由于if功力不足引出的Helper
    垂直方向兼容显示的内容多少的情况样式Flex布局
    实现div里的img图片水平垂直居中
  • 原文地址:https://www.cnblogs.com/lysuns/p/4324480.html
Copyright © 2020-2023  润新知