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
然后用一张图表示他们的属性:
lambda-introducer(也称为 capture 子句)
lambda declarator(也称为参数列表)
mutable(也称为可变规范)
exception-specification(也称为异常规范)
trailing-return-type(也称为返回类型)
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{ , }; }; // ERROR: return type is void, deducing
// return type from braced-init-list is not valid
auto x2 = [](int i) -> initializer_list<int>{return {, };}; //OK: return type is compatible
Lambda 体
lambda 表达式的 lambda 体(标准语法中的 compound-statement)可包含普通方法或函数的主体可包含的任何内容。 普通函数和 lambda 表达式的主体均可访问以下变量类型:
参数
本地声明变量
类数据成员(在类内部声明并且捕获 this 时)
具有静态存储持续时间的任何变量(例如,全局变量)
此外,lambda 表达式可以访问它从封闭范围中捕获的变量。 如果某个变量显示在 lambda 表达式的 capture 子句中,则该变量是显式捕获的。 否则,该变量是隐式捕获的。 lambda 表达式的主体使用默认捕获模式来访问隐式捕获的变量。
以下示例包含通过值显式捕获变量 n 并通过引用隐式捕获变量 m 的 lambda 表达式:
C++11中新特性之:lambda 表达式的更多相关文章
- java8新特性: lambda表达式:直接获得某个list/array/对象里面的字段集合
java8新特性: lambda表达式:直接获得某个list/array/对象里面的字段集合 比如,我有一张表: entity Category.java service CategoryServic ...
- Java8 新特性学习 Lambda表达式 和 Stream 用法案例
Java8 新特性学习 Lambda表达式 和 Stream 用法案例 学习参考文章: https://www.cnblogs.com/coprince/p/8692972.html 1.使用lamb ...
- JDK1.8新特性(一) ----Lambda表达式、Stream API、函数式接口、方法引用
jdk1.8新特性知识点: Lambda表达式 Stream API 函数式接口 方法引用和构造器调用 接口中的默认方法和静态方法 新时间日期API default Lambda表达式 L ...
- C++11新特性之一——Lambda表达式
C++11新特性总结可以参考:http://www.cnblogs.com/pzhfei/archive/2013/03/02/CPP_new_feature.html#section_6.8 C++ ...
- C++11新特性(3) lambda表达式(1)
C++11加入了一项名为lambda表达式的新功能.通过这项功能能编写内嵌的匿名函数,而不必编写独立函数或函数对象,使得代码更加理解. lambda表达式包括下面部分. [capture_block] ...
- C++11 新特性:Lambda 表达式
参考文章:https://blogs.oracle.com/pcarlini/entry/c_1x_tidbits_lambda_expressions 或许,Lambda 表达式算得上是 C++ 1 ...
- c++11 新特性之lambda表达式
写过c#之后,觉得c#里的lambda表达式和delegate配合使用,这样的机制用起来非常爽.c++11也有了lambda表达式,形式上有细小的差异.形式如下: c#:(input paramete ...
- jdk1.8新特性之lambda表达式及在Android Studio中的使用举例
Jdk1.8已经出很久了但是很多同学对它的特性在android studio 中的应用可能还不是很熟悉,今天我们就来对这个新特性在AS中做它的应用实践. 一.首先在有JDK1.8的情况下我们要在AS的 ...
- C++11 新特性之 Lambda表达式
lambda表达式能够用于创建并定义匿名的函数对象,以简化编程工作 Lambda的语法例如以下: [函数对象參数](操作符重载函数參数)->返回值类型{函数体} []内的參数指的是Lambda表 ...
随机推荐
- Oracle ABP(Autotask Background Process)
ABP相当于自动任务与调度程序之间的中介,其主要作用是将自动任务转换成Autotask作业,供调度程序执行.同样重要的是,ABP还维护所有任务执行的历史记录.ABP将其专用资料档案库存储在sysaux ...
- linux下启动某个进程
在关闭窗口的情况下,能够在后台继续运行,如 启动命令 node /home/node_modules/pixel-ping/lib/pixel-ping.js /home/node_modules/p ...
- _blank开新窗体不符合标准?
我们要在新窗体中打开链接通常的做法是在链接后面加target="_blank",我们採用过渡型的DOCTYPE(xh tml1-transitional. dtd)时没有问题,可是 ...
- stack例子
栈使用在括号匹配中的例子 程序如下: #include<stack> #include<iostream> using namespace std; int main() { ...
- LINUX 系统备份
系统备份是系统管理工作中十分重要的一个环切,本文详细介绍了各种Linux系统的备份方法,相信对大家的日常管理工作有所帮助. 备份是一项重要的工作,但是很多人没有去做.一旦由于使用不当造成数据丢失,备份 ...
- Android5.0之TextInputLayout、FloatingActionButton的使用
TextInputLayout和FloatingActionButton都属于MD风格的控件,比起普通的EditText和Button.ImageButton,TextInputLayout和Floa ...
- Docker container network configuration
http://xmodulo.com/networking-between-docker-containers.html How to set up networking between Docker ...
- 多版本uboot命令行分析
1.1.6 经典版本: 1.uboot第二阶段第一个函数void start_armboot (void),一路gd参数设置.设备初始化.控制台初始化.端口初始化,最后到main_loop ()命令行 ...
- 移动端 touch 实现 拖动元素
var homeMove = (function () { //touch自适应 var k = "ontouchend" in window ? "touchend&q ...
- 四种方式写按钮点击事件和Android 中常用的布局
1.匿名内部类的方式 2.创建一个类实现onClickListener,实现onClick方法,设置控件点击时传一个类的对象 3.让当前类实现onClickListener,设置控件点击事件时传递一个 ...