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中使用当前类的成员函数和成员变量。

[cpp] view plain copy
  1. class A
  2. {
  3. public:
  4. int i_ = 0;
  5. void func(int x,int y){
  6. auto x1 = [] { return i_; };                             //error,没有捕获外部变量
  7. auto x2 = [=] { return i_ + x + y; };               //OK
  8. auto x3 = [&] { return i_ + x + y; };               //OK
  9. auto x4 = [this] { return i_; };                        //OK
  10. auto x5 = [this] { return i_ + x + y; };            //error,没有捕获x,y
  11. auto x6 = [this, x, y] { return i_ + x + y; };    //OK
  12. auto x7 = [this] { return i_++; };                   //OK
  13. };
  14. int a=0 , b=1;
  15. auto f1 = [] { return a; };                            //error,没有捕获外部变量
  16. auto f2 = [&] { return a++ };                      //OK
  17. auto f3 = [=] { return a; };                         //OK
  18. auto f4 = [=] {return a++; };                     //error,a是以复制方式捕获的,无法修改
  19. auto f5 = [a] { return a+b; };                     //error,没有捕获变量b
  20. auto f6 = [a, &b] { return a + (b++); };      //OK
  21. auto f7 = [=, &b] { return a + (b++); };     //OK

注意的细节:

1.

  一个容易出错的细节是lambda表达式的延迟调用,lambda表达式按值捕获了所有外部变量。在捕获的一瞬间,a的值就已经被复制了。如果希望lambda表达式在调用时能即时访问外部变量,我们应当使用引用方式捕获。

[cpp] view plain copy
  1. int a = 0;
  2. auto f = [=] { return a; };
  3. a+=1;
  4. cout << f() << endl;       //输出0
  5. int a = 0;
  6. auto f = [&a] { return a; };
  7. a+=1;
  8. cout << f() <<endl;       //输出1

2.

  虽然按值捕获的变量值均补复制一份存储在lambda表达式变量中, 修改他们也并不会真正影响到外部,但我们却仍然无法修改它们。

  那么如果希望去修改按值捕获的外部变量,需要显示指明lambda表达式为mutable。

  需要注意:被mutable修饰的lambda表达式就算没有参数也要写明参数列表。
  原因:lambda表达式可以说是就地定义仿函数闭包的“语法糖”。它的捕获列表捕获住的任何外部变量,最终均会变为闭包类型的成员变量。按照C++标准,lambda表达式的operator()默认是const的,一个const成员函数是无法修改成员变量的值的。而mutable的作用,就在于取消operator()的const。

[cpp] view plain copy
  1. int a = 0;
  2. auto f1 = [=] { return a++; };                       //error
  3. auto f2 = [=] () mutable { return a++; };       //OK

3.

  没有捕获变量的lambda表达式可以直接转换为函数指针,而捕获变量的lambda表达式则不能转换为函数指针。原因可以参考2中的原因。

[cpp] view plain copy
  1. typedef void(*Ptr)(int*);
  2. Ptr p = [](int* p) { delete p; };              //OK
  3. Ptr p1 = [&] (int* p) { delete p; };         //error

最后,两个实际应用到lambda表达式的代码。

[cpp] view plain copy
  1. std::vector<int> v = { 1, 2, 3, 4, 5, 6 };
  2. int even_count = 0;
  3. for_each(v.begin(), v.end(), [&even_count](int val){
  4. if(!(val & 1)){
  5. ++ even_count;
  6. }
  7. });
  8. std::cout << "The number of even is " << even_count << std::endl;
[cpp] view plain copy
  1. int count = std::count_if( coll.begin(), coll.end(), [](int x){ return x > 10; });
  2. int count = std::count_if( coll.begin(), coll.end(), [](int x){ return x < 10; });
  3. int count = std::count_if( coll.begin(), coll.end(), [](int x){ return x > 5 && x<10; });

C++11 学习笔记 lambda表达式相关推荐

  1. kotlin学习笔记——lambda表达式

    先简单说说lambda表达式: (Type a, Type b, ...) -> {...} 左边是参数(参数类型可省略),如果只有一个参数括号也可以省略,右边是函数体和返回结果(大括号可省略) ...

  2. Java学习笔记---Lambda表达式及Stream流Api

    Lambda 特性: 允许把函数作为参数传递进方法. 前置条件: 必须是函数式接口---------->[函数式接口:满足以下三条1.接口中只有一个抽象方法.2.可以有默认实现的方法.3.可以有 ...

  3. main函数解析(一)——Linux-0.11 学习笔记(五)

    main()函数解析(一)--Linux-0.11 学习笔记(五) 经过了前面的各种铺垫,终于来到了main函数.这篇博客的任务是把init/main.c讲清楚.由于牵扯到很多的函数调用,要想一次就说 ...

  4. kernel_mktime() 详解 —— Linux-0.11 学习笔记(四)

    题目:kernel_mktime() 详解 -- Linux-0.11 学习笔记(四) 在init/main.c文件中,有一个函数static void time_init(void) 该函数读取 C ...

  5. 什么是C ++ 11中的lambda表达式?

    本文翻译自:What is a lambda expression in C++11? What is a lambda expression in C++11? 什么是C ++ 11中的lambda ...

  6. 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 ...

  7. setup.s 分析—— Linux-0.11 学习笔记(二)

    更新记录 版本 时间 修订内容 1.0 2018-4-14 增加了"获取显示模式"这一节,AL取值的表格 标题: setup.s 分析-- Linux-0.11 学习笔记(二) 老 ...

  8. 正则表达式学习笔记010--子表达式的认识与应用

    正则表达式学习笔记010--子表达式的认识与应用 交流群1:251572072 交流群2:170933152 子表达式: ()用2个小括号,括起来的叫做子表达式 如: \d{3,4}([\s|-]?\ ...

  9. C++ 11中的Lambda表达式

    1. 概述 C++ 11 中的 Lambda 表达式用于定义匿名类(anonymous class).创建匿名类对象,以简化编程工作.编译器为该类添加操作符重载函数void operator()(ar ...

最新文章

  1. [jQuery]使用jQuery.Validate进行客户端验证(高级篇-下)——不使用微软验证控件的理由...
  2. 图解 Hibernate,session.close(),session.clear()区别
  3. givemesomecredit数据_你是如何走上数据分析之路的?
  4. 《密码与安全新技术专题》第11周作业
  5. 启动mq 在虚拟机中_记在使用rocketmq client客户端过程中踩到的坑
  6. Description Resource Path Location Type Java compiler level does not match the version of the insta
  7. ABySS非root权限安装
  8. 求序列最长不下降子序列_树状数组解决最长不下降子序列 讲讲主要思路就好...
  9. Android通过Wifi来调试你的应用
  10. elasticsearch使用3:配置同义词词库、ik分词器扩展字典和扩展停止词字典
  11. 计算机管理即插即用服务,意外终止Plug and Play(即插即用)服务开启方法
  12. 第四周助教工作总结——NWNU李泓毅
  13. postgresql源码学习(38)—— 备份还原② - do_pg_stop_backup函数
  14. LaText Error:Environment aligned undefined.
  15. 索引及其背后的数据结构(顺带介绍了一下子查询和合并查询)
  16. “PaaS+云管”双剑合璧,BoCloud博云的进阶之路
  17. 【云原生 | Kubernetes 系列】---CephFS和OSS
  18. 连花清瘟对德尔塔病毒有效?这次网友反应不太一样
  19. 内存溢出如何Dump文件
  20. Bert Ertman专访:将Spring及遗留应用迁移到Java EE 6平台

热门文章

  1. MSSQL-字符串分离与列记录合并成一行混合使用
  2. ubunu安装软件的一个错误
  3. POJ 1860: Currency Exchange 【SPFA】
  4. 调整和改编赛车游戏——游戏屏幕
  5. linux中下载的服务压缩包存放在,linux 下tomcat6 配置为服务
  6. sqoop遇到mysql字段为保留字_关于在sqoop 导出数据到mysql数据库的过程对于空字符的处理。...
  7. java cpu过高排查_涨薪秘籍:JAVA项目排查cpu负载过高
  8. fedora 不在sudoers文件中_COPR 仓库中 4 个很酷的新软件(2019.4) | Linux 中国
  9. html如何让字体自动变色,CSS使文字部分变色
  10. php7如何安装swoole,PHP7如何安装Swoole?