C++11 学习笔记 lambda表达式
http://blog.csdn.net/fjzpdkf/article/details/50249287
lambda表达式是C++11最重要也最常用的一个特性之一。lambda来源于函数式编程的概念,也是现代编程语言的一个特点。
一.函数式编程简介
定义:简单说,“函数式编程”是一种“编程范式”。它属于“结构化编程”的一种,主要思想是把运算过程尽量写成一系列嵌套的函数调用。
特点:
1).函数是“第一等公民”,可以赋值给他其他变量,也可以做为参数,返回值。
2).只用“表达式”,不用“语句”。“表达式”是一个单纯的运算过程,总是有返回值;“语句”是执行某种操作,没有返回值。
3).没有副作用。函数保持独立,所有功能就是返回一个新的值,其他什么都不做,不修改外部变量的值。
4).引用透明。函数的运行不依赖于外部变量或“状态”,只依赖于输入的参数,只要参数相同,返回值就相同。
二.lambda表达式
lambda表达式有如下优点:
1).声明式编程风格:就地匿名定义目标函数或函数对象,不需要额外写一个命名函数或者函数对象。以更直接的方式去写程序,好的可读性和可维护性。
2).简洁:不需要额外再写一个函数或者函数对象,避免了代码膨胀和功能分散,让开发者更加集中精力在手边的问题,同时也获取了更高的生产率。
3).在需要的时间和地点实现功能闭包,使程序更灵活。
lambda表达式的语法归纳如下:
[ caputrue ] ( params ) opt -> ret { body; };
1).capture是捕获列表;
2).params是参数表;(选填)
3).opt是函数选项;可以填mutable,exception,attribute(选填)
mutable说明lambda表达式体内的代码可以修改被捕获的变量,并且可以访问被捕获的对象的non-const方法。
exception说明lambda表达式是否抛出异常以及何种异常。
attribute用来声明属性。
4).ret是返回值类型。(选填)
5).body是函数体。
捕获列表:lambda表达式的捕获列表精细控制了lambda表达式能够访问的外部变量,以及如何访问这些变量。
1).[]不捕获任何变量。
2).[&]捕获外部作用域中所有变量,并作为引用在函数体中使用(按引用捕获)。
3).[=]捕获外部作用域中所有变量,并作为副本在函数体中使用(按值捕获)。
4).[=,&foo]按值捕获外部作用域中所有变量,并按引用捕获foo变量。
5).[bar]按值捕获bar变量,同时不捕获其他变量。
6).[this]捕获当前类中的this指针,让lambda表达式拥有和当前类成员函数同样的访问权限。如果已经使用了&或者=,就默认添加此选项。捕获this的目的是可以在lamda中使用当前类的成员函数和成员变量。
- class A
- {
- public:
- int i_ = 0;
- void func(int x,int y){
- auto x1 = [] { return i_; }; //error,没有捕获外部变量
- auto x2 = [=] { return i_ + x + y; }; //OK
- auto x3 = [&] { return i_ + x + y; }; //OK
- auto x4 = [this] { return i_; }; //OK
- auto x5 = [this] { return i_ + x + y; }; //error,没有捕获x,y
- auto x6 = [this, x, y] { return i_ + x + y; }; //OK
- auto x7 = [this] { return i_++; }; //OK
- };
- int a=0 , b=1;
- auto f1 = [] { return a; }; //error,没有捕获外部变量
- auto f2 = [&] { return a++ }; //OK
- auto f3 = [=] { return a; }; //OK
- auto f4 = [=] {return a++; }; //error,a是以复制方式捕获的,无法修改
- auto f5 = [a] { return a+b; }; //error,没有捕获变量b
- auto f6 = [a, &b] { return a + (b++); }; //OK
- auto f7 = [=, &b] { return a + (b++); }; //OK
注意的细节:
1.
一个容易出错的细节是lambda表达式的延迟调用,lambda表达式按值捕获了所有外部变量。在捕获的一瞬间,a的值就已经被复制了。如果希望lambda表达式在调用时能即时访问外部变量,我们应当使用引用方式捕获。
- int a = 0;
- auto f = [=] { return a; };
- a+=1;
- cout << f() << endl; //输出0
- int a = 0;
- auto f = [&a] { return a; };
- a+=1;
- cout << f() <<endl; //输出1
2.
虽然按值捕获的变量值均补复制一份存储在lambda表达式变量中, 修改他们也并不会真正影响到外部,但我们却仍然无法修改它们。
那么如果希望去修改按值捕获的外部变量,需要显示指明lambda表达式为mutable。
需要注意:被mutable修饰的lambda表达式就算没有参数也要写明参数列表。
原因:lambda表达式可以说是就地定义仿函数闭包的“语法糖”。它的捕获列表捕获住的任何外部变量,最终均会变为闭包类型的成员变量。按照C++标准,lambda表达式的operator()默认是const的,一个const成员函数是无法修改成员变量的值的。而mutable的作用,就在于取消operator()的const。
- int a = 0;
- auto f1 = [=] { return a++; }; //error
- auto f2 = [=] () mutable { return a++; }; //OK
3.
没有捕获变量的lambda表达式可以直接转换为函数指针,而捕获变量的lambda表达式则不能转换为函数指针。原因可以参考2中的原因。
- typedef void(*Ptr)(int*);
- Ptr p = [](int* p) { delete p; }; //OK
- Ptr p1 = [&] (int* p) { delete p; }; //error
最后,两个实际应用到lambda表达式的代码。
- std::vector<int> v = { 1, 2, 3, 4, 5, 6 };
- int even_count = 0;
- for_each(v.begin(), v.end(), [&even_count](int val){
- if(!(val & 1)){
- ++ even_count;
- }
- });
- std::cout << "The number of even is " << even_count << std::endl;
- int count = std::count_if( coll.begin(), coll.end(), [](int x){ return x > 10; });
- int count = std::count_if( coll.begin(), coll.end(), [](int x){ return x < 10; });
- int count = std::count_if( coll.begin(), coll.end(), [](int x){ return x > 5 && x<10; });
C++11 学习笔记 lambda表达式相关推荐
- kotlin学习笔记——lambda表达式
先简单说说lambda表达式: (Type a, Type b, ...) -> {...} 左边是参数(参数类型可省略),如果只有一个参数括号也可以省略,右边是函数体和返回结果(大括号可省略) ...
- Java学习笔记---Lambda表达式及Stream流Api
Lambda 特性: 允许把函数作为参数传递进方法. 前置条件: 必须是函数式接口---------->[函数式接口:满足以下三条1.接口中只有一个抽象方法.2.可以有默认实现的方法.3.可以有 ...
- main函数解析(一)——Linux-0.11 学习笔记(五)
main()函数解析(一)--Linux-0.11 学习笔记(五) 经过了前面的各种铺垫,终于来到了main函数.这篇博客的任务是把init/main.c讲清楚.由于牵扯到很多的函数调用,要想一次就说 ...
- kernel_mktime() 详解 —— Linux-0.11 学习笔记(四)
题目:kernel_mktime() 详解 -- Linux-0.11 学习笔记(四) 在init/main.c文件中,有一个函数static void time_init(void) 该函数读取 C ...
- 什么是C ++ 11中的lambda表达式?
本文翻译自:What is a lambda expression in C++11? What is a lambda expression in C++11? 什么是C ++ 11中的lambda ...
- main 函数解析(二)—— Linux-0.11 学习笔记(六)
main函数解析(二)--Linux-0.11 学习笔记(六) 4.6 blk_dev_init函数 void blk_dev_init(void) {int i;for (i=0 ; i<NR ...
- setup.s 分析—— Linux-0.11 学习笔记(二)
更新记录 版本 时间 修订内容 1.0 2018-4-14 增加了"获取显示模式"这一节,AL取值的表格 标题: setup.s 分析-- Linux-0.11 学习笔记(二) 老 ...
- 正则表达式学习笔记010--子表达式的认识与应用
正则表达式学习笔记010--子表达式的认识与应用 交流群1:251572072 交流群2:170933152 子表达式: ()用2个小括号,括起来的叫做子表达式 如: \d{3,4}([\s|-]?\ ...
- C++ 11中的Lambda表达式
1. 概述 C++ 11 中的 Lambda 表达式用于定义匿名类(anonymous class).创建匿名类对象,以简化编程工作.编译器为该类添加操作符重载函数void operator()(ar ...
最新文章
- [jQuery]使用jQuery.Validate进行客户端验证(高级篇-下)——不使用微软验证控件的理由...
- 图解 Hibernate,session.close(),session.clear()区别
- givemesomecredit数据_你是如何走上数据分析之路的?
- 《密码与安全新技术专题》第11周作业
- 启动mq 在虚拟机中_记在使用rocketmq client客户端过程中踩到的坑
- Description Resource Path Location Type Java compiler level does not match the version of the insta
- ABySS非root权限安装
- 求序列最长不下降子序列_树状数组解决最长不下降子序列 讲讲主要思路就好...
- Android通过Wifi来调试你的应用
- elasticsearch使用3:配置同义词词库、ik分词器扩展字典和扩展停止词字典
- 计算机管理即插即用服务,意外终止Plug and Play(即插即用)服务开启方法
- 第四周助教工作总结——NWNU李泓毅
- postgresql源码学习(38)—— 备份还原② - do_pg_stop_backup函数
- LaText Error:Environment aligned undefined.
- 索引及其背后的数据结构(顺带介绍了一下子查询和合并查询)
- “PaaS+云管”双剑合璧,BoCloud博云的进阶之路
- 【云原生 | Kubernetes 系列】---CephFS和OSS
- 连花清瘟对德尔塔病毒有效?这次网友反应不太一样
- 内存溢出如何Dump文件
- Bert Ertman专访:将Spring及遗留应用迁移到Java EE 6平台
热门文章
- MSSQL-字符串分离与列记录合并成一行混合使用
- ubunu安装软件的一个错误
- POJ 1860: Currency Exchange 【SPFA】
- 调整和改编赛车游戏——游戏屏幕
- linux中下载的服务压缩包存放在,linux 下tomcat6 配置为服务
- sqoop遇到mysql字段为保留字_关于在sqoop 导出数据到mysql数据库的过程对于空字符的处理。...
- java cpu过高排查_涨薪秘籍:JAVA项目排查cpu负载过高
- fedora 不在sudoers文件中_COPR 仓库中 4 个很酷的新软件(2019.4) | Linux 中国
- html如何让字体自动变色,CSS使文字部分变色
- php7如何安装swoole,PHP7如何安装Swoole?