什么是Lambda?

C++ 11加入了一个非常重要的特性——Lambda表达式。营里(戴维营)的兄弟都对Objective-C很熟悉,许多人多block情有独钟,将各种回调函数、代理通通都用它来实现。甚至有人选择用FBKVOController、BlocksKit等开源框架将KVO、控件事件处理都改为通过block解决。原因就是简单、方便、直观,函数的定义和使用出现在同一个地方。这里的Lambda表达式实际上和block非常类似,当然如果你用它和Swift语言的闭包比较,那就是一回事了。下面先看几个Lambda和block的示例代码。

1 .Objective-C的block示例代码,使用^表示block类型,总体来说与函数指针的定义类似。

#import <Foundation/Foundation.h>int main()
{ void (^block)() = ^void() { NSLog(@"In block"); }; block(); return 0; } 

编译运行:

$ clang main.m -framework Foundation
$ ./a.out
2015-01-28 14:17:52.763 a.out[9901:165707] In block

2 .Swift的闭包,参数列表、返回值类型等都写在花括号{}内部。

let closure = {() -> Void in println("In swift") } closure() 

编译运行:

$ swiftc main.swift
$ ./main
In swift

测试Swift也可以直接使用Playground或REPL(Read-Eval-Print-Loop)环境。

3 .C++的Lambda表达式。

#include <iostream>int main()
{ auto lambda = []() -> void{ std::cout << "In lambda" << std::endl; }; lambda(); return 0; } 

编译运行,注意使用C++ 11的特性进行编译:

$ clang++ main.cpp -std=c++11
$ ./a.out
In lambda

Lambda、block实际上都是一个闭包(closure),它们都类似于一个匿名的函数,但是拥有捕获所在作用域中变量的能力;能够将函数做为对象一样使用。通常用它们来实现回调函数、代理等功能。

Lambda使用方法

1 .基本形式

语法 序号
[ 捕获列表 ] ( 形参数列表 ) mutable(可选) 异常属性 -> 返回值类型 { 函数体 } (1)
[ capture-list ] ( params ) -> ret { body } (2)
[ capture-list ] ( params ) { body } (3)
[ capture-list ] { body } (4)
  • (1)为完整的形式,包含变量捕获列表、形参列表、可变属性(可选)和返回值类型等。
  • (2)省略了mutable,表示Lambda不能修改捕获的变量。
  • Lambda的返回值类型如果可以由函数体中的实际返回值推导出,可以省略。
  • 如果没有形参,可以省略圆括号。

2 .捕获列表

lambda表达式中可以获取(捕获)它所在作用域中的变量值,并且有两种捕获方式:引用和值。我们可以在捕获列表中设置各变量的捕获方式。如果没有设置捕获列表,lambda默认不能捕获任何的变量,这点与block不同。

#include <iostream>int main()
{ int a = 123; auto lambda = []()->void{ std::cout << "In lambda: " << a << std::endl; }; lambda(); return 0; } 

编译运行:

$ clang++ main.cpp -std=c++11
main.cpp:8:33: error: variable 'a' cannot be implicitly captured in a lambdawith no capture-default specifiedstd::cout << "In lambda: " << a << std::endl;  ^ main.cpp:5:6: note: 'a' declared here int a = 123; ^ main.cpp:7:16: note: lambda expression begins here auto lambda = []()->void{ ^ 1 error generated. 

[]中设置捕获列表,就可以在lambda中使用变量a了,这里使用按值(=, by value)捕获。

#include <iostream>int main()
{ int a = 123; auto lambda = [=]()->void{ std::cout << "In lambda: " << a << std::endl; }; lambda(); return 0; } 

编译运行:

$ clang++ main.cpp -std=c++11
$ ./a.out
In lambda: 123

捕获列表的设置方式:

|设置方式|结果| |-|-| |[]|不捕获| |[=]|全部按值捕获| |[&]|全部按引用捕获| |[a, b]|按值捕获变量a和b| |[&a, b]|按引用捕获a,按值捕获b| |[&, a]|按值捕获a,其它变量全部按引用捕获| |[=, &a]|按引用捕获a,其它全部按值捕获|

注意: 捕获列表没有先后顺序;捕获列表中的变量不能出现重复申明,比如[&, &a]&中已经包含了&a的申明了,因此不能再出现&a

具体的捕获类型,可以通过打印变量地址进行查看。

  • 按值捕获:
auto lambda = [=]()->void{ std::cout << "In lambda: " << &a << std::endl; }; 

运行结果为:

$ clang++ main.cpp -std=c++11
$ ./a.out
0x7fff555c69b8
In lambda: 0x7fff555c69b0

  • 按引用捕获:
auto lambda = [&]()->void{ std::cout << "In lambda: " << &a << std::endl; }; 

运行结果为:

$ clang++ main.cpp -std=c++11
$ ./a.out
0x7fff58a9b9b8
In lambda: 0x7fff58a9b9b8

3 .可变类型(mutable)

按值传递到lambda中的变量,默认是不可变的(immutable),如果需要在lambda中进行修改的话,需要在形参列表后添加mutable关键字(按值传递无法改变lambda外变量的值)。

#include <iostream>int main()
{ int a = 123; std::cout << a << std::endl; auto lambda = [=]() mutable ->void{ a = 234; std::cout << "In lambda: " << a << std::endl; }; lambda(); std::cout << a << std::endl; return 0; } 

编译运行结果为:

$ clang++ main.cpp -std=c++11
lishan:c_study apple$ ./a.out
123
In lambda: 234  #可以修改 123 #注意这里的值,并没有改变 

如果没有添加mutable,则编译出错:

$ clang++ main.cpp -std=c++11
main.cpp:9:5: error: cannot assign to a variable captured by copy in anon-mutable lambdaa = 234; ~ ^ 1 error generated. 

4 .返回值类型。

lambda的返回值类型可以省略,编译器会根据实际返回值的类型自动推导。

#include <iostream>int main()
{ int a = 123; std::cout << a << std::endl; auto lambda = [=]() mutable{ a = 234; std::cout << "In lambda: " << a << std::endl; return a; }; int b = lambda(); std::cout << b << std::endl; return 0; } 

编译运行:

$ clang++ main.cpp -std=c++11
$ ./a.out
123
In lambda: 234
234

参考资料

  1. https://msdn.microsoft.com/en-us/library/dd293603.aspx
  2. http://www.oracle.com/technetwork/articles/servers-storage-dev/howto-use-lambda-exp-cpp11-2189895.html
  3. http://en.cppreference.com/w/cpp/language/lambda
  4. http://www.cprogramming.com/c++11/c++11-lambda-closures.html

本文档由长沙戴维营教育整理。

转载于:https://www.cnblogs.com/diveinedu/p/4335430.html

C++教程之lambda表达式一相关推荐

  1. python def函数_Python教程之Lambda表达式知识概述

    在Python中,除了def之外,还提供了一种生成函数对象的表达式形式,即Lambda表达式,它可以创建小的匿名函数,起到一个函数速写的作用.接下来的好程序员Python学习课程就给大家分享Lambd ...

  2. C++11 Lambda表达式

    1.简介 1.1定义 C++11新增了很多特性,Lambda表达式(Lambda expression)就是其中之一,很多语言都提供了 Lambda 表达式,如 Python,Java ,C#等.本质 ...

  3. java8 手把手教你学会写lambda表达式

    项目github地址:bitcarmanlee easy-algorithm-interview-and-practice 欢迎大家star,留言,一起学习进步 Java8发布已经有一段时间了,这次发 ...

  4. 小甲鱼python全部视频_小甲鱼全套教程之Python系列视频教程

    Python 当前位置:主页 > 编程教程 > Python > 小甲鱼全套教程之Python系列视频教程 小甲鱼全套教程之Python系列视频教程 教程大小:   发布时间:201 ...

  5. java lambda表达式_恕我直言你可能真的不会java第1篇:lambda表达式会用了么?

    本文配套教学视频:B站观看地址 在本号之前写过的一些文章中,笔者使用了lambda表达式语法,一些读者反映说代码看不懂.本以为java 13都已经出了,java 8中最重要特性lambda表达式大家应 ...

  6. 第三章:lambda表达式

    本文是学习Java8,参考JAVA8 IN ACTION这本书,学习整理以及自己的总结,推荐这本书: 1:Lambda 表达式 前篇文章讲到,使用匿名类来表示不同的行为并不令人满意:代码十分啰嗦,这会 ...

  7. javascript技术教程蔡敏_程序员都必掌握的前端教程之JavaScript基础教程(上)

    阅读本文约需要10分钟,您可以先关注我们,避免下次无法找到. 本篇文章成哥继续带大家来学习前端教程之JavaScript,网页的动态事件基本上都是靠它来实现的.下面我们就一起来学习内容吧! 01 Ja ...

  8. 艾伟_转载:使用Lambda表达式编写递归函数

    前言 著名的牛顿同学曾经说过:如果说我比别人看得更远些,那是因为我站在了巨人的肩上. 原文:If I have been able to see further, it was only becaus ...

  9. python Lambda 表达式

    来源:http://www.cnblogs.com/jydeng/p/4145188.html 一.lambda函数 1.lambda函数基础: lambda函数也叫匿名函数,即,函数没有具体的名称, ...

最新文章

  1. 从UV位置图获得3D人脸
  2. 微信小程序购物车 数量加减功能
  3. 马云湖畔大学开学致辞:企业家要比谁都相信未来
  4. Python在大部分领域都能胜任,为什么很多企业转向了Golang?
  5. 上传本地项目到githup(githup改版后将master改为main)
  6. pytorch---之固定某些层权重再训练
  7. hbase jdbc相关
  8. Ubuntu Linux 8.04 Vsftp 假造用户设置
  9. margin-left:10px; 不同浏览器距离为什么不一样?
  10. python下载微信公众号文章_python下载微信公众号相关文章
  11. 如何设计企业特色的数字化转型架构?
  12. AxureRP 8.0安装教程
  13. 解二元一次方程————拓展欧几里得算法
  14. 数据一致性、准确性、完整性、及时性、有效性
  15. (附源码)springboot宠物管理系统 毕业设计121654
  16. python爬虫和数据分析的书籍_豆瓣书籍数据爬取与分析
  17. mybatis代码自动生成工具之maven插件mybatis-generator-maven-plugin(mybatis逆向工程)
  18. ps2口键盘改usb计算机设置,轻松把PS2键盘、鼠标接口改造成USB接口
  19. oracle上亿数据的删除
  20. 百度云的高速下载技巧系列2---多线程文件下载工具idm v6.28.1绿色免注册版(PC)

热门文章

  1. 如何缩短visual studio行号的距离
  2. 读“ModSecurity配置关键字说明”之摘抄
  3. 《数据库SQL实战》查找当前薪水详情以及部门编号dept_no
  4. 如何在hadoop中控制map的个数
  5. 【转载】 Searching过程粗略梳理
  6. Spark入门 - History Server配置使用
  7. 20172307 2017-2018-2 《程序设计与数据结构》第9 周学习总结
  8. Hyper-v Server动态内存
  9. 微信公众平台开发(103) 四六级成绩查询
  10. aspxgridview 增加行号