lambda简介
熟悉Python的程序员应该对lambda不陌生。简单来说,lambda就是一个匿名的可调用代码块。在C++11新标准中,lambda具有如下格式:
[capture list] (parameter list) -> return type { function body }
可以看到,他有四个组成部分:
1.capture list: 捕获列表
2.parameter list: 参数列表
3.return type: 返回类型
4.function body: 执行代码
其中,参数列表和返回类型可以忽略。
下面,具体看几个简单的例子:
auto f1 = [] { return 1; }; auto f2 = [] () { return 2; }; cout<<f1()<<'\t'<<f2()<<endl;
捕获列表
lambda中的捕获列表既可以捕获值,也可以捕获引用。
捕获值:
int test_data[] = {1, 5, 9, 7, 3, 19, 13, 17}; int border = 8; auto f3 = [border](const int &i){ if(i > border) cout<<i<<'\t'; }; for_each(begin(test_data), end(test_data), f3); cout<<endl;
捕获引用:
auto f4 = [&border](const int &i){ if(i > border) cout<<i<<'\t'; }; border = 6; for_each(begin(test_data), end(test_data), f4); cout<<endl;
通过输出可以看出,lambda中起作用的border是修改后的6,证实了捕获的确是是引用。
需要注意的是,在捕获引用时,需要保证当lambda被调用时,此引用仍然有效。
捕获列表还可以采用隐式捕获的方式,即让编译器通过lambda的执行代码来判断需要捕获哪些局部变量。
隐式捕获可以捕获值、引用或者两者混合:
char space = ' '; auto f5 = [=](const int &i){ if(i > border) cout<<i<<'\t'; }; auto f6 = [&](const int &i){ if(i > border) cout<<i<<'\t'; }; auto f7 = [&, space](const int &i){ if(i > border) cout<<i<<space; }; border = 0; for_each(begin(test_data), end(test_data), f5); cout<<endl; for_each(begin(test_data), end(test_data), f6); cout<<endl; for_each(begin(test_data), end(test_data), f7); cout<<endl;
这里的f7使用的混合形式,可以读作“除了space捕获值之外,其他变量均捕获引用”。
可变lambda
当lambda需要在其中修改被值捕获的变量的值时,需要给lambda加上mutable关键字。否则会有编译错误。
auto f8 = [&, space](const int &i) mutable { if(i > border) {cout<<i<<space; space='\t';} }; for_each(begin(test_data), end(test_data), f8); cout<<endl; cout<<1<<space<<2<<endl;
从输出中可以看出,space在lambda f8中的值,在第一次调用之后,就被变成了制表符Tab;但是在lambda之外,space仍然是空格。
返回类型
lambda的返回类型采用尾置返回类型的方式。一般的:
1.lambda如果只包含return语句,则编译器可以推断其返回类型,此时可以不显示指定返回类型;
2.否则,编译器假定lambda返回void,而返回void的函数不可以反悔任何具体值,这在大多数情况下是个矛盾,因此需要显示指定返回类型。
但是,经过实际测试,目前的g++编译器更聪明了:对于第2点,目前只要编译器可以从lambda函数体中推断出函数的返回类型,就不需要显式指定返回类型,例如:
auto f9 = [](const int i){if(i % 3) return i * 3; else return i;}; transform(begin(test_data), end(test_data), begin(test_data), f9); border = 0; for_each(begin(test_data), end(test_data), f6); cout<<endl;
lambda代码块中有多个return语句,并且还有if/else语句,但是编译器可以根据return语句推断出,其返回值应该是一个int类型,所以可以省略尾置返回类型。
但是,像下面这种形式,由于编译器在推断返回类型时发现了不一致,所以必须显式的指定返回类型:
auto f10 = [](const int i) -> double {if(i % 5) return i * 5.0; else return i;}; transform(begin(test_data), end(test_data), begin(test_data), f10); for_each(begin(test_data), end(test_data), f6); cout<<endl;
总结
1.lambda表达式形式: [capture list] (parameter list) -> return type { function body },其中parameter list和return type可以省略。
2.捕获列表可以捕获值[val],也可以捕获引用[&ref]。
3.捕获列表还可以隐式捕获局部变量,同样有捕获值[=]和捕获引用[&]两种方式,初次之外还可以混合捕获[&, val]或者[=, &ref]。
4.当lambda需要修改捕获的值时,需要加上mutable关键字。
4.当lambda无法自动推断出返回值类型时,需要通过尾置返回类型的方式显示指定。
以上就是C++11新特性之Lambda表达式的全部内容,希望本文对大家学习C++有所帮助。
本文向大家介绍Java8新特性之Lambda表达式浅析,包括了Java8新特性之Lambda表达式浅析的使用技巧和注意事项,需要的朋友参考一下 说到java 8,首先会想到lambda(闭包)以及虚拟扩展方法(default method),这个特性早已经被各大技术网站炒得沸沸扬扬了,也是我们java 8系列开篇要讲的第一特性(JEP126 http://openjdk.java.net/jeps
本文向大家介绍结合C++11新特性来学习C++中lambda表达式的用法,包括了结合C++11新特性来学习C++中lambda表达式的用法的使用技巧和注意事项,需要的朋友参考一下 在 C++ 11 中,lambda 表达式(通常称为 "lambda")是一种在被调用的位置或作为参数传递给函数的位置定义匿名函数对象的简便方法。 Lambda 通常用于封装传递给算法或异步方法的少量代码行。 本文定义了
本文向大家介绍浅析C# 9.0 新特性之 Lambda 弃元参数,包括了浅析C# 9.0 新特性之 Lambda 弃元参数的使用技巧和注意事项,需要的朋友参考一下 大家好,这是 C# 9.0 新特性短系列的第 5 篇文章。 弃元(Discards) 是在 C# 7.0 的时候开始支持的,它是一种人为丢弃不使用的临时虚拟变量。语法上它是用来赋值的,但它却不被分配存储空间,即没有值,所以不能从中读取值
本文向大家介绍浅析python的Lambda表达式,包括了浅析python的Lambda表达式的使用技巧和注意事项,需要的朋友参考一下 在python项目中,我们经常会用到lambda,那么lambda是什么呢,有什么作用,下面我们开始介绍 1、可以使用lambda关键字创建匿名函数。Lambda函数可以在需要函数对象的任何地方使用。它们在语法上限于单个表达式。所谓匿名就是无名。 例如定义两个书加
本文向大家介绍一文带你入门JDK8新特性——Lambda表达式,包括了一文带你入门JDK8新特性——Lambda表达式的使用技巧和注意事项,需要的朋友参考一下 Lambda简介 Lambda 表达式是 JDK8 的一个新特性,可以取代大部分的匿名内部类,写出更优雅的 Java 代码,尤其在集合的遍历和其他集合操作中,可以极大地优化代码结构。 JDK 也提供了大量的内置函数式接口供我们使用,使得 L
1. ENUM枚举 1.1 枚举概述 枚举是指将变量的值一一列出来,变量的值只限于列举出来的值的范围内。举例:一周只有7天,一年只有12个月等。 回想单例设计模式:单例类是一个类只有一个实例 那么多例类就是一个类有多个实例,但不是无限个数的实例,而是有限个数的实例。这才能是枚举类。 格式是:只有枚举项的枚举类 public enum 枚举类名 { 枚举项1,枚举项2,枚举项3…;