Lambda 表达式语法

本主题介绍 lambda 表达式的语法。 它演示提供 lambda 表达式的结构元素的示例,这些元素与示例。

Lambda 表达式语法

下面用于定义显示语法,ISO C++11 从标准,lambda 表达式 (项标记下标 选择 是可选的):

         lambda-introducer lambda-declarator 选择 compound-statement

进一步失败的组件这些语法如下:

lambda-introducer: 
         [ lambda-capture 选择 ] 
lambda-capture:
        capture-default
        capture-list
         capture-default , capture-list 
capture-default:
        &
        =
capture-list:
         capture ... 选择 
         capture-list , capture ... opt 
capture:
        identifier
         & identifier 
        this
lambda-declarator:
         ( parameter-declaration-clause ) mutable 选择 
                 exception-specification 选择 attribute-specifier-seq 选择 trailing-return-type 选择 

Visual Studio 支持 C++11 标准 Lambda 表达式语法及其所有 C++11 功能与除了 lambda,以下操作:

  • 要,任何其他类,不会自动生成的构造函数并将不根据标准要求将赋值运算符。 有关 rvalue 引用行为支持的更多信息,请参见 对 C++11 功能的支持(现代 C++)中的 Rvalue References 节。
  • 可选的 attribute-specifier-seq 不支持。

Visual Studio 向 C++11 lambda 功能通过添加以下功能:

    • 无状态是 lambda omni 转换的任意函数使用调用约定的函数的指针。
    • 比 { return expression; } 复杂的主体的 lambda 自动返回这样的类型,只要所有返回语句具有相同的类型。(这在 C++14 标准现在建议的)。

Lambda 表达式的属性

下图将该语法映射到示例。

图中的标注如下所示:

  1. lambda-introducer(在本主题的后面称为“capture 子句”)
  2. lambda declarator(在本主题的后面称为“参数列表”)
  3. mutable(在本主题的后面称为“可变规范”)
  4. exception-specification(在本主题的后面称为“异常规范”)
  5. trailing-return-type(在本主题的后面称为“返回类型”)
  6. compound-statement(在本主题的后面称为“lambda 体”)

以下各节对该语法进行了更详细的说明。

Capture 子句

lambda 表达式是类、构造和函数调用运算符。 如同,在定义类时,决定需要发生的对象捕获变量不受值还是引用或者是否是必需的。 如果 lambda 表达式需要访问局部变量和函数参数,它们需要 捕获。 get 子句 (语法中的lambda-introducer ) 所指定 lambda 表达式的主体是可以访问在封闭范围内的变量通过值或通过引用:包含" &的变量 (&) 为前缀) 没有 & 前缀的引用和变量访问值由访问。

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

捕获默认模式指定您未显式指定的获取变量是否捕获通过值或通过引用,如果使用它们。 您可以通过将 & 或 = 指定为 capture 子句的第一个元素来指定默认捕获模式(语法中的 capture-default)。 & 元素指定 lambda 表达式的主体通过引用访问所有捕获的变量,除非您显式地另行指定。 = 元素指定 lambda 表达式的主体通过值访问所有捕获的变量,除非您显式地另行指定。 例如,如果 lambda 表达式的主体通过引用访问外部变量 total 并通过值访问外部变量 factor,那么以下 capture 子句等效:

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

有关使用 capture-default 的一种常见的误会位于范围内的任何变量捕获是否使用 lambda。 事实上并非如此 - 在 lambda 提到的那些变量捕获,则使用 capture-default。

如果捕获子句包括 capture-default&,该 lambda 的 get 子句 capture 的 identifier 不能由 &。 沿着同一行,因此,如果获取子句包括 capture-default (=),该子句获得每个 capture 必须以窗体 & identifier。 标识符或 this 不能多次出现在子句获得。 下面的代码段阐释了一些示例。

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 后跟是 pack 扩展,以下面的示例:variadic 模板

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

可以将 lambda 表达式用于类方法的主体中。 将 this 指针传递到 capture 子句以提供对封闭类的方法和数据成员的访问权限。 有关示例演示如何使用类用方法的 lambda 表达式,请参见示例:使用将方法的 Lambda 表达式。主题 Lambda 表达式的示例

在使用子句获得时,应记住这些,理解和压力,尤其当使用具有多线程时的 lambda:

  • 引用获取可用于修改变量之外,获取值,而无法用于修改变量之外 (变量允许复制修改,从原始的)。
  • 而值获取不会反映更新给变量,则获取引用会反映更新到变量中。
  • 而值获取没有生存期依赖关系,这些依赖关系的引用,获取引入生存期依赖关系,这些依赖关系。

许多这些点在这和相关文章中的代码示例所示。

参数列表

参数列表 (lambda declarator) lambda 表达式中为选项并类似于函数的参数列表。

lambda 表达式可以将另一个 lambda 表达式作为其参数。 有关详细信息,请参阅主题 Lambda 表达式的示例中的“高阶 Lambda 表达式”。

lambda 表达式的参数列表可以是可选的。 可以省略空括号,如果不传递参数到 lambda 表达式,并且 lambda-declarator: 不包含 exception-specification、trailing-return-type、mutable。

可变规范

通常的 lambda 函数调用运算符为 Const 按值,但是,mutable 可以取消此操作。 它不导致变量的数据成员。 可变规范使用 lambda 表达式的主体修改由捕获值的变量。 某些示例本文后面演示了 mutable 关键字的用法。

异常规范

您可以使用 throw() 异常规范来指示 lambda 表达式不会引发任何异常。 与正则函数一样,如果 lambda 表达式声明 throw() 异常规范且 lambda 体引发异常,Visual C++ 编译器将生成警告 C4297,如以下示例所示:

// throw_lambda_expression.cpp
// compile with: /W4 /EHsc
int main() // C4297 expected
{
   []() throw() { throw 5; }();
}

返回类型

lambda 表达式的返回类型自动推断,并且,这发生,而无需添加关键字,除非指定 trailing-return-type。auto trailing-return-type 类似于普通方法或函数返回类型的部件。 但是,遵循返回类型参数列表,您必须包括尾部的返回类型关键字 ->,在返回类型。

如果 lambda 体包含单个返回语句或 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 not valid

lambda 表达式可以生成另一个 lambda 表达式作为其返回值。 有关详细信息,请参阅主题 Lambda 表达式的示例中的“高阶 Lambda 表达式”。

Lambda 体

lambda 表达式主体的 lambda (compound-statement) 中可以包含一般的方法或函数主体所能包含的所有内容。 普通函数和 lambda 表达式的主体均可访问以下变量类型:

  • 参数
  • 本地声明变量
  • 类数据成员 (在声明类和 this 内捕获)
  • 具有静态存储持续时间的任何变量(例如,全局变量)

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

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

// captures_lambda_expression.cpp
// compile with: /W4 /EHsc
#include <iostream>
using namespace std;

int main()
{
   int m = 0;
   int n = 0;
   [&, n] (int a) mutable { m = ++n + a; }(4);
   cout << m << endl << n << endl;
}

本示例将以下内容输出到控制台:

5
0

由于变量 n 是通过值捕获的,因此在调用 lambda 表达式后,变量的值仍保持 0 不变。 指定 mutable 允许 n 是在 lambda 中修改。

尽管 lambda 表达式只能捕获具有自动存储持续时间的变量,但您可以在 lambda 表达式的主体中使用具有静态存储持续时间的变量。 以下示例使用 generate 函数和 lambda 表达式为 vector 对象中的每个元素赋值。 lambda 表达式将修改静态变量以生成下一个元素的值。

void fillVector(vector<int>& v)
{
    // A local static variable.
    static int nextValue = 1;

    // The lambda expression that appears in the following call to
    // the generate function modifies and uses the local static
    // variable nextValue.
    generate(v.begin(), v.end(), [] { return nextValue++; });
    //WARNING: this is not thread-safe and is shown for illustration only
}

有关 generate 函数的详细信息,请参阅 生成

下面的代码示例使用从前面的函数,并将该表达式的 lambda 表达式的示例与 STL generate_n的算法。 该 lambda 表达式分配的 vector 对象的元素。前两个元素的和的。 改用 mutable 关键字,这样 lambda 表达式体才能改变其外部变量 x 和 y的复制,lambda 表达式按值捕获。 由于 lambda 表达式按值捕获原始变量 x 和 y,它们的值保持为 1,在 lambda 后执行。

// compile with: /W4 /EHsc
#include <algorithm>
#include <iostream>
#include <vector>
#include <string>

using namespace std;

template <typename C> void print(const string& s, const C& c) {
    cout << s;

    for (const auto& e : c) {
        cout << e << " ";
    }

    cout << endl;
}

void fillVector(vector<int>& v)
{
    // A local static variable.
    static int nextValue = 1;

    // The lambda expression that appears in the following call to
    // the generate function modifies and uses the local static
    // variable nextValue.
    generate(v.begin(), v.end(), [] { return nextValue++; });
    //WARNING: this is not thread-safe and is shown for illustration only
}

int main()
{
    // The number of elements in the vector.
    const int elementCount = 9;

    // Create a vector object with each element set to 1.
    vector<int> v(elementCount, 1);

    // These variables hold the previous two elements of the vector.
    int x = 1;
    int y = 1;

    // Sets each element in the vector to the sum of the
    // previous two elements.
    generate_n(v.begin() + 2,
        elementCount - 2,
        [=]() mutable throw() -> int { // lambda is the 3rd parameter
        // Generate current value.
        int n = x + y;
        // Update previous two values.
        x = y;
        y = n;
        return n;
    });
    print("vector v after call to generate_n() with lambda: ", v);

    // Print the local variables x and y.
    // The values of x and y hold their initial values because
    // they are captured by value.
    cout << "x: " << x << " y: " << y << endl;

    // Fill the vector with a sequence of numbers
    fillVector(v);
    print("vector v after 1st call to fillVector(): ", v);
    // Fill the vector with the next sequence of numbers
    fillVector(v);
    print("vector v after 2nd call to fillVector(): ", v);
}
vector v after call to generate_n() with lambda: 1 1 2 3 5 8 13 21 34
x: 1 y: 1
vector v after 1st call to fillVector(): 1 2 3 4 5 6 7 8 9
vector v after 2nd call to fillVector(): 10 11 12 13 14 15 16 17 18

 

				
时间: 2024-10-26 00:45:44

Lambda 表达式语法的相关文章

java中lambda表达式语法说明_java

语法说明 一个lambda表达式由如下几个部分组成: 1. 在圆括号中以逗号分隔的形参列表.在CheckPerson.test方法中包含一个参数p,代表了一个Person类的实例.注意:lambda表达式中的参数的类型是可以省略的:此外,如果只有一个参数的话连括号也是可以省略的.比如上一节曾提到的代码: p -> p.getGender() == Person.Sex.MALE && p.getAge() >= 18 && p.getAge() <= 25

Java8初体验(一)lambda表达式语法

感谢同事[天锦]的投稿.投稿请联系 tengfei@ifeve.com 本文主要记录自己学习Java8的历程,方便大家一起探讨和自己的备忘.因为本人也是刚刚开始学习Java8,所以文中肯定有错误和理解偏差的地方,希望大家帮忙指出,我会持续修改和优化.本文是该系列的第一篇,主要介绍Java8对屌丝码农最有吸引力的一个特性-lambda表达式. java8的安装 工欲善其器必先利其器,首先安装JDK8.过程省略,大家应该都可以自己搞定.但是有一点这里强调一下(Windows系统):目前我们工作的版本

lambda表达式

什么时候使用lambda表达式 lambda表达式定义 lambda表达式语法 lambda表达式理解 lambda表达式使用 lambda表达式的泛型使用 什么时候使用lambda表达式 如果一段代码需要延迟执行,就可以使用lambda表达式,如在另外的线程运行的一段代码.需要在某个时间点运行的代码.某个条件触发回调的代码等. lambda表达式定义 lambda表达式是一段可以传递的.可以执行的代码.之所以叫这个名字是因为lambda表达式是一个带参数变量的表达式,而在数学里面带参数的表达式

一个Java 8中简单Lambda表达式程序

原文链接 作者:   Mohamed Sanaulla  译者: 李璟(jlee381344197@gmail.com) 我尝试过把Lambda表达式融入到我的代码中,下面的代码例子是此次尝试的结果.对于那些完全不知道Lambda表达式的Java程序员,我强烈建议在继续阅读之前,浏览一下这篇文章. Ok,现在你已经熟悉Lambda表达式了(在阅读过推荐的Lambda入门文章之后),那我们现在开始学习一个我认为很好的Lambda表达式的例子. 考虑一下这种场景:某些操作在执行之前需要做预处理,执行

了解Lambda表达式和接口类更改如何使得Java 8成为一种新语言

接口更改使得接口可以添加到现有接口中,同时又不会破坏与现有代码的兼容性.本文将了解这些更改是如何http://www.aliyun.com/zixun/aggregation/18521.html">协同工作的,请阅读本文的姊妹篇 "Java 8 并发性基础",了解如何对 Java 8 streams 使用 lambdas. Java 8 的最大变化在于添加了对 lambda 表达式 的支持.Lambda 表达式是可按引用传递的代码块.它们类似于一些其他编程语言中的闭包

Java8新特性之Lambda表达式浅析_java

说到java 8,首先会想到lambda(闭包)以及虚拟扩展方法(default method),这个特性早已经被各大技术网站炒得沸沸扬扬了,也是我们java 8系列开篇要讲的第一特性(JEP126 http://openjdk.java.net/jeps/126),jdk8的一些库已经应用了lambda表达式重新设计了,理解他对学习java 8新特性有着重要的意义. 一.函数式接口 函数式接口(functional interface 也叫功能性接口,其实是同一个东西).简单来说,函数式接口是

Java 8中简单Lambda表达式实例程序教程

我尝试过把Lambda表达式融入到我的代码中,下面的代码例子是此次尝试的结果.对于那些完全不知道Lambda表达式的Java程序员,我强烈建议在继续阅读之前,浏览一下这篇文章. Ok,现在你已经熟悉Lambda表达式了(在阅读过推荐的Lambda入门文章之后),那我们现在开始学习一个我认为很好的Lambda表达式的例子. 考虑一下这种场景:某些操作在执行之前需要做预处理,执行之后需要做后期处理.待执行的操作会随着行为的不同而变化.预处理会提取出这个操作所需的必要参数,后期处理做一些清理的工作.

Lambda表达式和linq普通语法的一些对比

  linq普通语法 return (from p in dc.TeacherBasicInformation where p.TeacherNum == num select p.PhotoSrc).FirstOrDefault();             Lambda表达式 return dc.TeacherBasicInformation.Where(p => p.TeacherNum == num).Select(p => p.PhotoSrc).FirstOrDefault();

[C#]Lambda表达式和Where语法

之前一直以为C#中Lambda表达式和Where语法很神圣,看人家写出一串这样的代码出来都感觉好高深,其实只是不敢接触而已,然后今晚看了一下,仔细理解一下也很简单!看例子: [code]csharpcode: 01 using System; 02 using System.Collections.Generic; 03 using System.Linq; 04 05 06 07 namespace Lambda 08 { 09     class Program 10     { 11