提示:文章
文章目录
- 前言
- 一、背景
- 在使用lambda的时候,有几个参数是可以直接省略的:
- 二、题目
- 问题探究
- 总结
前言
前期疑问:
本文目标:
lamda表达式
一、背景
看c++科二的时候有看到lamda表达式,就再次看了下
这次稍微有点看懂
lamda表达式结构:
lambda的结构是:[ ] () -> 返回值类型 { }。从左到右依次是:捕捉列表 函数参数 -> 返回值类型 函数体。
解析上述的结构
在使用lambda的时候,有几个参数是可以直接省略的:
1.参数列表可以省略(写() 或者不写())。
2.返回值可以省略(不写 -> 类型)。
除此之外的东西都不可省略(捕捉列表,函数体实现)。
上述变化最多的应该就是捕捉列表。
[ ] | 不捕捉任何变量 | |
---|---|---|
[var] | 表示值传递方式捕捉变量var | 显式捕捉 |
[=] | 表示值传递方式捕获所有父作用域中的变量(包括this) | 隐式捕捉 |
[&var] | 表示引用传递捕捉变量var; | 显式捕捉;可以改变变量值 |
[&] | 表示引用传递捕捉所有父作用域中的变量(包括this); | 隐式捕捉;可以改变变量值 |
[this] | 捕获当前类中的 this 指针 |
a. 父作用域指包含lambda函数的语句块
b. 语法上捕捉列表可由多个捕捉项组成,并以逗号分割。
比如:[=, &a, &b]:以引用传递的方式捕捉变量a和b,值传递方式捕捉其他所有变量 [&,a, this]:值传递方式捕捉变量a和this,引用方式捕捉其他变量
auto fun1 = [&](int c) {b = a + c; };
fun1(10);
cout << a << " " << b << endl;
c. 捕捉列表不允许变量重复传递,否则就会导致编译错误。 比如:[=, a]:=已经以值传递方式捕捉了所有变量,捕捉a重复
int x = 10;
auto add_x = [x, =](int a) mutable { x *= 2; return a + x; };
cout << add_x(10) << endl;
d. 在块作用域以外的lambda函数捕捉列表必须为空。
e. 在块作用域中的lambda函数仅能捕捉父作用域中局部变量,捕捉任何非此作用域或者非局部变量都会导致编译报错。
f. lambda表达式之间不能相互赋值,即使看起来类型相同
lambda表达式实际上可以理解为无名函数,该函数无法直接调用,如果想要直接调用,可借助auto将其赋值给一个变量。
参考文档:C++入门——“C++11-lambda”
c++11新特性:lambda表达式
Lambda表达式
二、题目
下面加上喂饭宝典的几个题目。
1、(单选)【lambda】下面代码运行结果是(B)
int n = 1;
auto func1 = [=] { return n; };
auto func2 = [&] { return n; };
n++;
cout<<func1()<<" "<<func2()<<endl;
A. 1 1
B. 1 2
C. 2 2
D. 2 1
解释:Lambda 表达式的 [] 用来确定捕获参数:
[=]:捕获的局部变量只可读不可写,捕获范围是当前 Lambda 表达式之前的作用域。
[&]:捕获的局部变量可读可写。
2、(单选)【lambda】如下程序的输出结果是(D)
#include <functional>using namespace std;auto g1(int x)
{return [&x](int y) { return x + y; };
}auto g2(int& x)
{return [&x](int y) { return x + y; };
}int main()
{int x = 1;auto f1 = g1(x);auto f2 = g2(x);cout<<f1(2)<<,<<f2(2)<<endl;x = 2;cout<<f1(2)<<,<<f2(2)<<endl;return 0;
}
A. 3,3,3,4
B. 3,3,4,4
C. 不确定,3,不确定,3
D. 不确定,3,不确定,4
解释:g1 按引用捕获了局部变量,函数退出局部变量引用就不确定了,所以输出也是不确定的
3、(单选)【lambda】以下代码输出是(B)
void ShowLambda()
{int var = 5;static int base = 3;auto func = [=]() mutable {++base;++var;return base + var;};auto ret1 = func();auto ret2 = func();cout<<ret1<<" "<<ret2<<" "<<var<<" "<<base<<endl;
}int main()
{ShowLambda();return 0;
}
A. 10 12 5 3
B. 10 12 5 5
C. 10 10 5 5
D. 12 12 7 5
解释:
lambda表达式相当于创建了一个struct,把var变成了私有变量。
另外每个lambda表达式即使参数相同,也会新建不同的对象,如auto a = []{}; auto b = []{},a和b所有内部变量不共享,因为它们被视为两个不同的函数
[=]为值传递 int变量会在函数里面进行++操作,函数外面又恢复原值。注意静态变量,与引用传递和值传递无关,
4、(单选)【lambda】以下代码输出是
void ShowLambda(){int var = 5;static int base = 3;auto func = [&]() mutable {++base;++var;return base + var;};base++;var++;auto ret1 = func();auto ret2 = func();std::cout << "ret1 = " << ret1 << ", ret2 = " << ret2 << ",var = " << var << ", base = " << base << std::endl;}
答案:ret1 = 12, ret2 = 14, var = 8, base = 6
解释:【&】地址传递,int变量值也会增加
注意[=] 和 [&]的区别
如果改成func = [=]() mutable
则输出ret1 = 11, ret2 = 13, var = 6, base = 6
问题探究
其中针对第四题,自己写了验证代码
void ShowLambda2()
{int var = 5;static int base = 3;auto func = [&]() mutable {++base;++var;return base + var;};auto ret1 = func();auto ret2 = func();std::cout << "ret1 = " << ret1 << ", ret2 = "<< ret2 << ",var = " << var << ", base = " << base << std::endl;
}//预测10 11 6 5 实际 10 12 7 5,理解就是传引用变量值会被更改并保留void ShowLambda()
{int var = 5;static int base = 3;auto func = [=]() mutable {++base;++var;return base + var;};auto ret1 = func();auto ret2 = func();std::cout << "ret1 = " << ret1 << ", ret2 = "<< ret2 << ",var = " << var << ", base = " << base << std::endl;
}// 预测报错或者10, 11, 5, 5 实际10 12 5,5 理解可能虽然按值传递,但是在同一作用域内,变量会累计自增变化
// ?????这边无法理解为什么ret2为12。。。。void ShowLambda4()
{int var = 5;static int base = 3;auto func = [&]() mutable {++base;++var;return base + var;};std::cout << "var = " << var << ", base = " << base << std::endl; // 这边打印验证,经过lamda定义语句时不会对变量发生改变base++;var++;auto ret1 = func();auto ret2 = func();std::cout << "ret1 = " << ret1 << ", ret2 = "<< ret2 << ",var = " << var << ", base = " << base << std::endl;
}// 预测 12 14 8 6,实际也为12 14 8 6。理解就是捕捉的val为5,base为3,因为传的是引用,随着自增后val为6,base为4,func函数内部自增后val为7,base为5,和为12。
// 第二次执行func,此时val为7,base为5,因为传引用,此时随着自增后val为8,base为6,所以和为14。void ShowLambda5()
{int var = 5;static int base = 3;auto func = [=]() mutable {++base;++var;return base + var;};std::cout << "var = " << var << ", base = " << base << std::endl;base++;var++;auto ret1 = func();auto ret2 = func();std::cout << "ret1 = " << ret1 << ", ret2 = "<< ret2 << ",var = " << var << ", base = " << base << std::endl;
}// 预测 12 14 8 6 实际 11 ,13, 6 ,6 理解就是虽然base和val在函数定义后面++,但是base和val的值在lamda函数表达式在定义时已经捕捉。所以func执行时,val为5,base虽然一开始被捕捉时是3,但是受自增影响后为4,在函数内部自增后,val为6, base为5,相加ret1为11。
// 第二次执行func,val依然为5,base此时为5,在函数内部都自增后,val为6,base为6,相加为12。
总结
未完待续