本主题介绍 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 ; }();
}

返回类型

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{ , }; }; // 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 = ;
int n = ;
[&, n] (int a) mutable { m = ++n + a; }();
cout << m << endl << n << endl;
}

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


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

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

void fillVector(vector<int>& v)
{
// A local static variable.
static int nextValue = ; // 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 = ; // 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 = ; // Create a vector object with each element set to 1.
vector<int> v(elementCount, ); // These variables hold the previous two elements of the vector.
int x = ;
int y = ; // Sets each element in the vector to the sum of the
// previous two elements.
generate_n(v.begin() + ,
elementCount - ,
[=]() 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:
x: y:
vector v after 1st call to fillVector():
vector v after 2nd call to fillVector():

Lambda 表达式语法的更多相关文章

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

    感谢同事[天锦]的投稿.投稿请联系 tengfei@ifeve.com 本文主要记录自己学习Java8的历程,方便大家一起探讨和自己的备忘.因为本人也是刚刚开始学习Java8,所以文中肯定有错误和理解 ...

  2. Java8 lambda表达式语法 1

    本文主要记录自己学习Java8的历程,方便大家一起探讨和自己的备忘.因为本人也是刚刚开始学习Java8,所以文中肯定有错误和理解偏差的地方,希望大家帮忙指出,我会持续修改和优化.本文是该系列的第一篇, ...

  3. Java8初体验(1):lambda表达式语法

    原文出处: 一冰_天锦 本文主要记录自己学习Java8的历程,方便大家一起探讨和自己的备忘.因为本人也是刚刚开始学习Java8,所以文中肯定有错误和理解偏差的地方,希望大家帮忙指出,我会持续修改和优化 ...

  4. Lambda表达式语法

    基础语法:‘->’Lambda操作符* 左侧:Lambda表达式的参数列表 对应接口中方法中的参数列表中的参数(比如nice1中MyPredict这个接口中的方法)* 右侧:Lambda表达式中 ...

  5. java8【一、lambda表达式语法】

    特点 lambda表达式允许将函数作为方法的参数 lambda表达式更加简洁 特征 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值. 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需 ...

  6. Lambda表达式语法进一步巩固

    上一次已经初步使用到了Lambda表达式了,这次再次对它的语法进行一下巩固,因为它实在是太重要的,所以多花时间彻底理解它是非常有必要的. 在"Java8 in Action"一书中 ...

  7. JDK8--03:lambda表达式语法

    对于lambda表达式的基础语法,一个是要了解lambda表达式的基础语法,另外一个是需要了解函数式接口 一.lambda表达式基础语法描述 java8中引入了新的操作符  ->  ,可以称为l ...

  8. Lambda表达式语法2

    package airycode_java8.nice3; import airycode_java8.nice1.Employee; import org.junit.Test; import ja ...

  9. Lambda表达式的语法与如何使用Lambda表达式

    Lambda表达式是对象,是一个函数式接口的实例 如何来写Lambda表达式? 看参数 看返回值 代码实例1: package day2; import jdk.nashorn.internal.co ...

随机推荐

  1. 自定义指令directive基础用法

    官方链接:http://doc.vue-js.com/v2/guide/custom-directive.html#simplest-directive-example 在main.js中注册自定义指 ...

  2. JavaWeb学习—思维导图

  3. Spring Boot—11控制器Controller

    package com.sample.smartmap.controller; import org.springframework.beans.factory.annotation.Autowire ...

  4. ida不错的插件记录

    IDASkins 地址 https://github.com/zyantific/IDASkins 作用 ida黑色皮肤插件 IDAFuzzy 地址 https://github.com/Ga-ryo ...

  5. Android 运行时权限处理(from jianshu)

    https://www.jianshu.com/p/e1ab1a179fbb 翻译的国外一篇文章. android M 的名字官方刚发布不久,最终正式版即将来临! android在不断发展,最近的更新 ...

  6. 2018-10-13 21:30:51 conversion of number systems

    2018-10-13 21:30:51  c language 二进制.八进制和十六进制: 1) 整数部分 十进制整数转换为 N 进制整数采用“除 N 取余,逆序排列”法. 十进制数字 36926 转 ...

  7. oracle数据泵备份(Expdp命令)

    Oracle备份方式主要分为数据泵导出备份.热备份与冷备份三种,今天首先来实践一下数据泵备份与还原.数据泵导出/导入属于逻辑备份,热备份与冷备份都属于物理备份.oracle10g开始推出了数据泵(ex ...

  8. C++易混淆概念

    1. 引用和指针有什么区别? 本质:一个是别名,一个是地址1. 指针可以在运行时改变其所指向的值,引用一旦和某个对象绑定就不再改变2. 引用没有const, 指针有const 3. 从内存上看,指针会 ...

  9. [翻译] PTEHorizontalTableView

    PTEHorizontalTableView Horizontal UITableView inspired by EasyTableView. 水平滚动的UITableView,灵感来自于EasyT ...

  10. September 07th 2017 Week 36th Thursday

    With the most true of yourself, can you meet the most suitable one. 用最真实的自己,才能遇见最合适的那个人. You are alw ...