-
c++ lambda表达式
2017-08-31 16:16:25c++ lambda表达式简单来说,Lambda函数也就是一个函数,它的语法定义如下:
[capture](parameters) mutable ->return-type{statement}
分别为:捕获列表,参数,关键字修饰(const mutable等),返回类型,函数体
1.[capture]:捕捉列表。捕捉列表总是出现在Lambda函数的开始处。实际上,[]是Lambda引出符。编译器根据该引出符判断接下来的代码是否是Lambda函数。捕捉列表能够捕捉上下文中的变量以供Lambda函数使用;
2.(parameters):参数列表。与普通函数的参数列表一致。
3.mutable:mutable修饰符。默认情况下,Lambda函数总是一个const函数,mutable可以取消其常量性。
4.->return-type:返回类型。用追踪返回类型形式声明函数的返回类型。我们可以在不需要返回值的时候也可以连同符号”->”一起省略。此外,在返回类型明确的情况下,也可以省略该部分,让编译器对返回类型进行推导;
5.{statement}:函数体。内容与普通函数一样,不过除了可以使用参数之外,还可以使用所有捕获的变量。
与普通函数最大的区别是,除了可以使用参数以外,Lambda函数还可以通过捕获列表访问一些上下文中的数据。具体地,捕捉列表描述了上下文中哪些数据可以被Lambda使用,以及使用方式(以值传递的方式或引用传递的方式)。语法上,在“[]”包括起来的是捕捉列表,捕捉列表由多个捕捉项组成,并以逗号分隔。
其调用方式与函数类似,实例如下:
#include <stdio.h>
#include <stdlib.h>
#include <fstream>
#include <iostream>
using namespace std;
int main()
{
/*
[=] 采用值捕获方式捕获所有父作用域的变量(包括this指针)
[var]采用值捕获方式捕获父作用域的变量var
[&]采用引用捕获方式捕获父作用域所用变量
[&var]采用引用捕获方式捕获父作用域的变量var
捕获列表里可以用,号隔开捕获多个变量。
注意:采用值捕获的方式捕获的变量,看lambda函数有没被mutable修饰,有则捕获的变量可以作左值,否则捕获的变量为在lambda函数里为常量;采用引用捕获方式捕获的变量,在lambda函数里是一个变量。
*/
int a =10;
//auto func = [=]()->int{return a=0;};错误,[=]采用值捕获方式,捕获所有在函数体内的所有的实体值,在lambda函数里默认都是const型,不能作为左值
auto func1 = [=]()mutable->int{return a = 0;};//正确,因为lambda表达式中的mutable关键字可以取消其常属性。lambda默认表达式时const属性,在该属性下不能修改成员变量值。
auto func = [&a]()->int{return a =1;};//正确,[&a]采用引用捕获方式,捕获变量a,在lambda函数里是变量,可以作为左值。
auto fund = [&a]()->int{return a=11;};
cout<<fund();
//没有返回值时可以省略->return_type如:
auto fun1 = []{printf("fffff\n");};
fun1();//调用方式与函数类似,无参数
auto fun2 = [](int a){printf("%d\n",a);};
fun2(10);//有参数情况
auto fun3 = []{return 1;};//可以忽略参数列表和返回类型
auto fun4 = [](){return 0;};//可以忽略返回类型
//auto fun5 = [=]->int{return a};//错误不能这么写,需写参数即使参数为空
system("pause");
return 0;
} -
C++ lambda表达式
2020-07-28 17:15:41与函数类似,**lambda表达式**...《C++ Primer》中提到一个lambda表达式表示一个可调用的代码单元,可以将其理解为一个未命名的内联函数。本笔记参考《C++ Primer》,主要对C++ lambda表达式的用法进行一个简单的记录。与函数类似,lambda表达式也是一种可调用对象,但其可以定义在函数内部。《C++ Primer》中提到一个lambda表达式表示一个可调用的代码单元,可以将其理解为一个未命名的内联函数。本笔记参考《C++ Primer》,主要对C++ lambda表达式的用法进行一个简单的记录。
用法简介
当需要一个实现简单功能的可调用对象时,使用lambda表达式可以使得代码更为简洁。在一些泛型算法中可以直接传入lambda表达式自定义规则,比如sort第三个参数直接写个lambda表达式指定排序规则。
lambda表达式的形式如下:
[capture list](parameter list) -> return type {function body} 即
[捕获列表](参数列表) -> 返回类型 {函数体} 捕获列表用来放置在lambda表达式所在函数中定义的需要传入lambda表达式的局部变量。其余部分的含义与函数定义中对应的部分相同。不过lamdba必须使用尾置返回。lambda表达式中,参数列表和返回类型可以省略,捕获列表(尽管可能为空)和函数体必须存在。调用lambda表达式的方法也与调用普通函数一样,使用调用运算符
()
即可。简单示例
简单的lambda表达式及调用示例如下,该示例捕获列表为空,没有参数列表和返回类型,函数体也仅仅是返回一个字符串。
auto fun = [] { return "Hello world!"; }; cout << fun() << endl;//输出Hello world!
参数传递
lambda表达式传递参数的方式也与函数类似,使用给定实参初始化形参,通常实参和形参类型必须匹配。下面给出一个示例。
auto fun = [](const string &s1, const string & s2) { return s1 + ' ' + s2; }; string s1 = "Hello"; string s2 = "world"; cout << fun(s1,s2) << endl;//输出Hello world
捕获列表的使用
通过捕获列表,我们可以在lambda表达式中使用lambda表达式所在函数中定义的局部变量。
值捕获和引用捕获
采用值捕获,被捕获的变量的值是在lambda创建时拷贝。下面的示例中,变量a在lambda创建时被捕获,完成了值的拷贝,因此当a的值改变后,再调用lambda发现并不起作用。
int a = 1; auto fun = [a](int b) { return a + b; }; int b = 1; cout << a << ' ' << b << endl;//输出1 1 cout << fun(b) << endl;//输出2 a += 1; cout << a << ' ' << b << endl;//输出2 1 cout << fun(b) << endl;//输出2
引用捕获的示例如下
int a = 1; auto fun = [&a](int b) { return a + b; }; int b = 1; cout << a << ' ' << b << endl;//输出1 1 cout << fun(b) << endl;//输出2 a += 1; cout << a << ' ' << b << endl;//输出2 1 cout << fun(b) << endl;//输出3
隐式捕获
使用隐式捕获,就可以不显式列出要在lambda表达式要捕获的变量,取而代之的是让编译器通过lambda表达式中的代码来推断使用的变量。在捕获列表中写个
=
指示使用值捕获方式,写个&
指示使用引用捕获方式。int a = 1; auto fun = [=](int b) { return a + b; };//[]中写个=,使用值捕获方式 int b = 1; cout << a << ' ' << b << endl;//输出1 1 cout << fun(b) << endl;//输出2 a += 1; cout << a << ' ' << b << endl;//输出2 1 cout << fun(b) << endl;//输出2
int a = 1; auto fun = [&](int b) { return a + b; };//[]中写个&,使用引用捕获方式 int b = 1; cout << a << ' ' << b << endl;//输出1 1 cout << fun(b) << endl;//输出2 a += 1; cout << a << ' ' << b << endl;//输出2 1 cout << fun(b) << endl;//输出3
可以混用显式捕获和隐式捕获。不过若隐式部分使用值捕获方式,则显式部分就不能用值捕获方式,反之,隐式部分使用引用捕获方式,则显式部分就不能用引用捕获方式。
int a = 1; int b = 1; auto fun = [&, b](int c) { return a + b + c; }; int c = 1; cout << fun(b) << endl;//输出3
显式捕获和隐式捕获用同一种方式提示错误:
当然,要是不用隐式捕获,捕获列表中各变量的捕获方式就随便写。尾声:就简单记录这么多,一般我自己也很少用到复杂的情况。
-
C++lambda表达式
2018-08-12 16:24:36C++lambda表达式 lambda表达式的引入的主要目的是,让您能够使用表达式用作接受函数指针或函数符的函数的参数 for_each(numbers.begin(),numbers.end(),[&count13](int x){ count13 += x % 13 == 0; ...C++lambda表达式
lambda表达式的引入的主要目的是,让您能够使用表达式用作接受函数指针或函数符的函数的参数
for_each(numbers.begin(),numbers.end(),[&count13](int x){ count13 += x % 13 == 0; });
for_each是stl库的一个函数,最后一个参数可以接受函数符,函数指针以及lambda表达式
lambda表达式的编写
[]省略了函数名称以及返回值 相当于使用decltype自动推断返回类型
但值得注意的是,只有在函数完全由一条返回语句组成时,自动推断才生效,否则要使用返回类型后置
auto mod2 = [] (int x) -> int { int y = x ; return y;} ;
可以为lambda表达式指定一个名称,借此重复使用lambda表达式
lambda表达式的名称也可以像普通函数一样使用
auto mod3 = [] (int x) { return x%3 == 0 ; }; int count1 = count_if(numbers.begin(),numbers.end(),mod3); int count2 = count_if(numbers.begin(),numbers.end(),mod3); bool result = mod3(3); cout << count1 <<" "<< count2 <<" "<< result <<" "<< endl;
lambda的额外功能
lambda可访问作用域内的任何动态变量
把要捕获的变量放在[]内,可以按值或按引用访问变量
按值访问时,直接输入变量名[count2] (int x) { return x%3 == 0 ; };
按引用访问时,加上& ;
/** * [&count13]让lambda能够在其代码中使用count13 * 由于count13是按引用捕获的,因此在lambda中对于count13的任何修改都会影响到原始count13 **/ count13 = 0; for_each(numbers.begin(),numbers.end(),[&count13](int x){ count13 += x % 13 == 0; }); cout << "using lambda : count of numbers divisible by 13: " << count13 <<endl;
[&]能够按引用访问作用域内的所有动态变量 ; [=]能够按值访问作用域内所有动态变量
在这里&让lambda能够按照引用访问所有的动态变量
count3=count13=0; for_each(numbers.begin(),numbers.end(), [&](int x) {count13 += x % 13 == 0; count3 += x % 3 ==0;}); cout << "using lambda : count of numbers divisible by 3: " << count3 <<endl; cout << "using lambda : count of numbers divisible by 13: " << count13 <<endl;
捕获和&=也可以组合起来使用,下式表示,按值访问ted并按引用访问其他所有动态变量
[&,ted] ... {...}
为什么使用lambda
距离:一般来说,我们都希望定义位于使用附近的地方,这样在修改代码时,涉及的代码都在附近而不用翻阅很多页去找寻函数的定义的位置
简洁:相对于函数符和函数,lambda表达式都要更简洁
效率:可以在函数内部定义有名称的lambda,lambda的效率取决于编译器的实现方式
功能:lambda表达式具有额外的功能(如上文所示)
-
C++ Lambda表达式
2020-11-13 14:34:07C++11中的Lambda表达式用于定义并创建匿名的函数对象,以简化编程工作。 ①函数对象参数; [],标识一个Lambda的开始,这部分必须存在,不能省略。函数对象参数是传递给编译器自动生成的函数对象类的构造函数的。...一、Lambda表达式的基本构成:
C++11中的Lambda表达式用于定义并创建匿名的函数对象,以简化编程工作。
① 函数对象参数;
[],标识一个Lambda的开始,这部分必须存在,不能省略。函数对象参数是传递给编译器自动生成的函数对象类的构造函数的。函数对象参数只能使
用那些到定义Lambda为止时Lambda所在作用范围内可见的局部变量(包括Lambda所在类的this)。函数对象参数有以下形式:
-
- 空。没有使用任何函数对象参数。
- =。函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是值传递方式(相当于编译器自动为我们按值传递了所有局部变量)。
- &。函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是引用传递方式(相当于编译器自动为我们按引用传递了所有局部变量)。
- this。函数体内可以使用Lambda所在类中的成员变量。
- a。将a按值进行传递。按值进行传递时,函数体内不能修改传递进来的a的拷贝,因为默认情况下函数是const的。要修改传递进来的a的拷贝,可以添加mutable修饰符。
- &a。将a按引用进行传递。
- a, &b。将a按值进行传递,b按引用进行传递。
- =,&a, &b。除a和b按引用进行传递外,其他参数都按值进行传递。
- &, a, b。除a和b按值进行传递外,其他参数都按引用进行传递。
② 操作符重载函数参数;
标识重载的()操作符的参数,没有参数时,这部分可以省略。参数可以通过按值(如:(a,b))和按引用(如:(&a,&b))两种方式进行传递。
③ 可修改标示符;
mutable声明,这部分可以省略。按值传递函数对象参数时,加上mutable修饰符后,可以修改按值传递进来的拷贝(注意是能修改拷贝,而不是值本身)。
④ 函数返回值;
->返回值类型,标识函数返回值的类型,当返回值为void,或者函数体中只有一处return的地方(此时编译器可以自动推断出返回值类型)时,这部分可以省略。
⑤ 是函数体;
{},标识函数的实现,这部分不能省略,但函数体可以为空。
二、代码和测试输出
#include <iostream> using namespace std; class A { public : A(int aa, int bb) :a(aa), b(bb) {} int b; void test() { [this]() { cout << this->b << endl; }(); } private: int a; }; //[](){} 是一个匿名函数 //[](){}() 是匿名函数的调用 void test1(void) { cout << "test1:Lambda test[]:"; int a = 100; []() { //不能使用任何对象 //cout << a << endl; cout << "不能使用任何对象" << endl; }(); } void test2(void) { cout << "test2 :Lambda test[=]:"; int a = 100; [=]() { //函数体内可以使用Lambda所在作用范围内所有可见的局部变量 //但是不能改变局部变量的值 //a += 100; cout << a << endl; }(); } void test3(void) { cout << "test3:Lambda test[&]:" ; int a = 100; [&]() { //函数体内可以使用Lambda所在作用范围内所有可见的局部变量 //但是不能改变局部变量的值 a += 100; cout << a << endl; }(); cout << a << endl; } void test4() { cout << "test4:Lambda test[this]:" ; A *p = new A(100,50); p->test(); delete p; } void test5() { cout << "test5: Lambda test mutable:"; //mutable声明,这部分可以省略。按值传递函数对象参数时,加上mutable修饰符后, //可以修改按值传递进来的拷贝(注意是能修改拷贝,而不是值本身)。 int a = 100; [a]()mutable { a += 100; cout << a << endl; }(); cout << a << endl; //a的值并没有改变 } void test6() { cout << "test6:Lambda test return value:"; //->返回值类型,标识函数返回值的类型,当返回值为void, //或者函数体中只有一处return的地方(此时编译器可以自动推断出返回值类型)时, //这部分可以省略。 int res = []()->int { return 100; }(); cout << res << endl; } int main() { test1(); cout << endl; test2(); cout << endl; test3(); cout << endl; test4(); cout << endl; test5(); cout << endl; test6(); cout << endl; return 0; }
-
-
c++ Lambda表达式
2019-04-11 20:15:31Lambda表达式(C++11引入) Lambda语法 Lambda表达式是一种能够捕获作用域中变量的无名函数对象,也是构造闭包的方式。 常见语法如下: [ captures ] ( params ) -> ret { body } 其中captures为捕获的变量列表,... -
C++ Lambda 表达式
2020-03-16 11:44:25声明Lambda表达式 [capture list] (params list) mutable exception-> return type { function body } 各项具体含义如下 capture list:捕获外部变量列表 params list:形参列表 mutable指示符:用... -
C++Lambda表达式
2019-07-25 23:06:33C++11引入的Lambda表达式可以快速的得到某些只调用1次的函数,可以理解成匿名函数,方便阅读时直接了解到调用函数的功能。 注意在例如cb、dev中编译设置要有-stdc++11,因为这是11的标准,这个表达式可以结合着auto...
-
psnuffle嗅探
-
LeetCode刷题——345. 反转字符串中的元音字母
-
高中地理湘教版必修一水循环.docx
-
【MyBatis】执行原理(二):创建会话(SqlSession) 源码分析
-
高负载脉宽可调双池受激布里渊散射系统的实验研究
-
【MyBatis】架构分层及主要对象
-
java实现递归二分查找法
-
vue3从0到1-超详细
-
fakexposed-debug-1.1-all.apk
-
使用 Linux 平台充当 Router 路由器
-
TFS安装与管理
-
Scala基础-源码
-
深究字符编码的奥秘,与乱码说再见
-
Samba 服务配置与管理
-
常用选择器
-
MyWeixinShop-master.zip
-
高中地理湘教版必修二人口迁移.docx
-
Glasterfs 分布式网络文件系统
-
Study on digital holography with single phase-shifting operation
-
【硬核】一线Python程序员实战经验分享(1)