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

[cpp] view plain copy
  1. class A  
  2. {  
  3. public:  
  4.     int i_ = 0;  
  5.       
  6.     void func(int x,int y){  
  7.         auto x1 = [] { return i_; };                             //error,没有捕获外部变量  
  8.         auto x2 = [=] { return i_ + x + y; };               //OK  
  9.         auto x3 = [&] { return i_ + x + y; };               //OK  
  10.         auto x4 = [this] { return i_; };                        //OK  
  11.         auto x5 = [this] { return i_ + x + y; };            //error,没有捕获x,y  
  12.         auto x6 = [this, x, y] { return i_ + x + y; };    //OK  
  13.         auto x7 = [this] { return i_++; };                   //OK  
  14. };  
  15.   
  16. int a=0 , b=1;  
  17. auto f1 = [] { return a; };                            //error,没有捕获外部变量      
  18. auto f2 = [&] { return a++ };                      //OK  
  19. auto f3 = [=] { return a; };                         //OK  
  20. auto f4 = [=] {return a++; };                     //error,a是以复制方式捕获的,无法修改  
  21. auto f5 = [a] { return a+b; };                     //error,没有捕获变量b  
  22. auto f6 = [a, &b] { return a + (b++); };      //OK  
  23. 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.   
  4. a+=1;  
  5.   
  6. cout << f() << endl;       //输出0  
  7.   
  8.   
  9. int a = 0;  
  10. auto f = [&a] { return a; };  
  11.   
  12. a+=1;  
  13.   
  14. 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.   
  3. Ptr p = [](int* p) { delete p; };              //OK  
  4. 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.   
  3. int count = std::count_if( coll.begin(), coll.end(), [](int x){ return x < 10; });  
  4.   
  5. int count = std::count_if( coll.begin(), coll.end(), [](int x){ return x > 5 && x<10; });  


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/384206.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Cutting Codeforces Round #493 (Div. 2)

Cutting There are a lot of things which could be cut — trees, paper, “the rope”. In this problem you are going to cut a sequence of integers. There is a sequence of integers, which contains the equal number of even and odd numbers. Given a limited bud…

Enum、Stream

Enum 其常见用法见&#xff1a;https://cloud.tencent.com/developer/section/1116852 在sort时&#xff0c;如果要获得稳定的排序结果&#xff0c;要使用< 而不是 <。 Stream Stream是延迟处理的&#xff0c;而Enum是贪婪的&#xff0c;则意味着传给它一个收集&#xff…

linux网络编程之posix 线程(三):posix 匿名信号量与互斥锁 示例生产者--消费者问题

http://blog.csdn.net/jnu_simba/article/details/9123603 一、posix 信号量 信号量的概念参见这里。前面也讲过system v 信号量&#xff0c;现在来说说posix 信号量。 system v 信号量只能用于进程间同步&#xff0c;而posix 信号量除了可以进程间同步&#xff0c;还可以线程间…

洛谷P1080-国王游戏-贪心+高精度

P1080-国王游戏 啊啊啊&#xff0c;刚才已经写了一次了&#xff0c;但是Edge浏览器不知道为什么卡住了&#xff0c;难受。 好吧&#xff0c;其实是一道可做题&#xff0c;分析得到的贪心策略就是就是将a * b小的放在前面&#xff08;其他的懒得说了&#xff09;&#xff0c;主要…

字符串与二进制

单引号字符串会被表示成整数值列表。 &#xff1f;c返回字符 c 的整数编码。下面这个例子用于解析字符列表表示法&#xff0c;该表示法用于表示一个任意的有符号的十进制数据。 defmodule Parse dodef number([ ?- | tail ]) do_number_digits(tail, 0) * -1enddef number([ ?…

P1092虫食算-深度优先搜索+玄学剪枝

P1092虫食算 这道题的思想并不复杂&#xff0c;可是难点在于各种玄学剪枝。在仔细研究了题解大佬的剪枝原理后终于氵了过去。 先上代码&#xff1a; #include<cstdio> #include<cstring> #include<algorithm> using namespace std;const int MAXN100; int n…

多进程

使用spawn创建一个新进程&#xff0c;其第一个参数是模块名、第二个参数是函数名、第三个参数是参数列表。spawn会返回一个进程标识符&#xff0c;通常叫做PID。 defmodule Spawn1 dodef greet doreceive do{sender, msg} ->send sender, { :ok, "Hello #{msg}" }…

Linux socket编程(二) 服务器与客户端的通信

http://www.cnblogs.com/-Lei/archive/2012/09/04/2670964.html上一篇写了对套接字操作的封装&#xff0c;这一节使用已封装好的Socket类实现服务器与客户端的通信&#xff08;Socket的定义见上篇Socket.h) 服务器端&#xff1a; ServerSocket.h #ifndef SERVERSOCKET_H #defin…

OTP服务器

defmodule Sequence.Server douse GenServerdef handle_call( :next_number, _from, current_number) do{ :reply, current_number, current_number 1}  #reply告诉OTP将第二个元素返回给客户端end end use的效果将OTP GenServer的行为添加到当前模块。这样它就可以处理所有…

洛谷P1040-加分二叉树-dp+二叉树

P1040-加分二叉树 这道题放在深度优先搜索的训练题中&#xff0c;可是我实在没有看出来应该怎么搜索。看了题解以后才看出来是一个很简单的dp(我果然还是太菜了) 看出dp并且算出来最大的分数不是很复杂&#xff0c;关键是输出给定中序遍历序列的二叉树的先序遍历&#xff0c;要…

UNIX网络编程:I/O复用技术(select、poll、epoll)

http://blog.csdn.net/dandelion_gong/article/details/51673085 Unix下可用的I/O模型一共有五种&#xff1a;阻塞I/O 、非阻塞I/O 、I/O复用 、信号驱动I/O 、异步I/O。此处我们主要介绍第三种I/O符复用。 I/O复用的功能&#xff1a;如果一个或多个I/O条件满足&#xff08;输…

解决iex -S mix报错

执行iex -S mix命令的时候会遇到如下错误&#xff1a; 执行 mix deps.get 然后就可以运行 iex -S mix了 其中&#xff0c;有可能会出现 按照其网站下载相应文件&#xff0c;复制到项目根目录下&#xff0c;然后执行命令&#xff08;mix local.rebar rebar ./rebar&#xff09;即…

贪心算法——选择不相交区间问题

题目描述&#xff1a;设有n个活动的集合&#xff0c;其中每个活动都要求使用同一个资源&#xff0c;而在同一时间内只有一个活动能够使用这一资源&#xff0c;每个活动i都有一个要求使用该资源的起始时间si和一个结束时间fi(si<fi)&#xff0c;如果选择了活动i&#xff0c;则…

Anker—工作学习笔记

http://www.cnblogs.com/Anker/archive/2013/08/17/3263780.html 1、基本知识 epoll是在2.6内核中提出的&#xff0c;是之前的select和poll的增强版本。相对于select和poll来说&#xff0c;epoll更加灵活&#xff0c;没有描述符限制。epoll使用一个文件描述符管理多个描述符&am…

Supervisor监控

可参考&#xff1a;https://www.cnblogs.com/wang_yb/archive/2016/06/08/5564459.html &#xff1a;https://segmentfault.com/a/1190000007379204 转载于:https://www.cnblogs.com/lr1402585172/p/11551488.html

深度搜索剪枝——数的划分

【题目描述】将整数n分成k份&#xff0c;且每份不能为空&#xff0c;问有多少种分法&#xff1f; 【输入格式】两个整数n,m(6<n<200,2<m<6) 【输出格式】输出不同的分法数 【样例输入】7 3 【样例输出】4 对于这种搜索题&#xff0c;关键就在于剪枝&#xff1a;确定…

Linux网络编程——tcp并发服务器(I/O复用之select

http://blog.csdn.net/lianghe_work/article/details/46519633 与多线程、多进程相比&#xff0c;I/O复用最大的优势是系统开销小&#xff0c;系统不需要建立新的进程或者线程&#xff0c;也不必维护这些线程和进程。 代码示例&#xff1a; [csharp] view plaincopy #include &…

ets

:ets.new(table_name, pattern) 第一个参数是表名&#xff0c;第二个参数是表的设置选项。 :set  一个key&#xff0c;一个数据&#xff0c;无序 :ordered_set  一个key&#xff0c;一个数据&#xff0c;有序&#xff1b; 1 1.0 :bag  一个key&#xff0c;多个数据&…

贪心算法-区间选点问题-种树

【题目描述】一条街道的一边有几座房子。因为环保原因居民想要在路边种些树&#xff0c;路边的地区被分割成n块&#xff0c;并被编号为1~n。每块大小为一个单位尺寸且最多可总一棵树。每个居民想在门前种些树并制定了三个数b,e,t&#xff0c;这三个数代表居民想在b和e之间最少种…

ets注意事项

当表类型为 :set 时&#xff0c;使用 :ets.first 和 :ets.last 会获取到同一个 key。将表类型换为 :oedered_set 就可以避免这种情况 转载于:https://www.cnblogs.com/lr1402585172/p/11599219.html