C++教程之lambda表达式一
什么是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
参考资料
- https://msdn.microsoft.com/en-us/library/dd293603.aspx
- http://www.oracle.com/technetwork/articles/servers-storage-dev/howto-use-lambda-exp-cpp11-2189895.html
- http://en.cppreference.com/w/cpp/language/lambda
- http://www.cprogramming.com/c++11/c++11-lambda-closures.html
本文档由长沙戴维营教育整理。
转载于:https://www.cnblogs.com/diveinedu/p/4335430.html
C++教程之lambda表达式一相关推荐
- python def函数_Python教程之Lambda表达式知识概述
在Python中,除了def之外,还提供了一种生成函数对象的表达式形式,即Lambda表达式,它可以创建小的匿名函数,起到一个函数速写的作用.接下来的好程序员Python学习课程就给大家分享Lambd ...
- C++11 Lambda表达式
1.简介 1.1定义 C++11新增了很多特性,Lambda表达式(Lambda expression)就是其中之一,很多语言都提供了 Lambda 表达式,如 Python,Java ,C#等.本质 ...
- java8 手把手教你学会写lambda表达式
项目github地址:bitcarmanlee easy-algorithm-interview-and-practice 欢迎大家star,留言,一起学习进步 Java8发布已经有一段时间了,这次发 ...
- 小甲鱼python全部视频_小甲鱼全套教程之Python系列视频教程
Python 当前位置:主页 > 编程教程 > Python > 小甲鱼全套教程之Python系列视频教程 小甲鱼全套教程之Python系列视频教程 教程大小: 发布时间:201 ...
- java lambda表达式_恕我直言你可能真的不会java第1篇:lambda表达式会用了么?
本文配套教学视频:B站观看地址 在本号之前写过的一些文章中,笔者使用了lambda表达式语法,一些读者反映说代码看不懂.本以为java 13都已经出了,java 8中最重要特性lambda表达式大家应 ...
- 第三章:lambda表达式
本文是学习Java8,参考JAVA8 IN ACTION这本书,学习整理以及自己的总结,推荐这本书: 1:Lambda 表达式 前篇文章讲到,使用匿名类来表示不同的行为并不令人满意:代码十分啰嗦,这会 ...
- javascript技术教程蔡敏_程序员都必掌握的前端教程之JavaScript基础教程(上)
阅读本文约需要10分钟,您可以先关注我们,避免下次无法找到. 本篇文章成哥继续带大家来学习前端教程之JavaScript,网页的动态事件基本上都是靠它来实现的.下面我们就一起来学习内容吧! 01 Ja ...
- 艾伟_转载:使用Lambda表达式编写递归函数
前言 著名的牛顿同学曾经说过:如果说我比别人看得更远些,那是因为我站在了巨人的肩上. 原文:If I have been able to see further, it was only becaus ...
- python Lambda 表达式
来源:http://www.cnblogs.com/jydeng/p/4145188.html 一.lambda函数 1.lambda函数基础: lambda函数也叫匿名函数,即,函数没有具体的名称, ...
最新文章
- 从UV位置图获得3D人脸
- 微信小程序购物车 数量加减功能
- 马云湖畔大学开学致辞:企业家要比谁都相信未来
- Python在大部分领域都能胜任,为什么很多企业转向了Golang?
- 上传本地项目到githup(githup改版后将master改为main)
- pytorch---之固定某些层权重再训练
- hbase jdbc相关
- Ubuntu Linux 8.04 Vsftp 假造用户设置
- margin-left:10px; 不同浏览器距离为什么不一样?
- python下载微信公众号文章_python下载微信公众号相关文章
- 如何设计企业特色的数字化转型架构?
- AxureRP 8.0安装教程
- 解二元一次方程————拓展欧几里得算法
- 数据一致性、准确性、完整性、及时性、有效性
- (附源码)springboot宠物管理系统 毕业设计121654
- python爬虫和数据分析的书籍_豆瓣书籍数据爬取与分析
- mybatis代码自动生成工具之maven插件mybatis-generator-maven-plugin(mybatis逆向工程)
- ps2口键盘改usb计算机设置,轻松把PS2键盘、鼠标接口改造成USB接口
- oracle上亿数据的删除
- 百度云的高速下载技巧系列2---多线程文件下载工具idm v6.28.1绿色免注册版(PC)