Lambda 表达式
0.什么是Lambda表达式?
他其实与函数功能类似,如上,我们在641定义了一个ADD函数计算两个int的和,在647调用该函数打印2与1相加的结果。同样的,我们的Lambda表达式也是定义好之后在646调用打印了结果。而后者具备更灵活的操作:
如上,我们在642-644定义并直接调用了表达式,用结果初始化res变量,然后再打印出来。我们发现Lambda表达式有一个好处:不用吭哧吭哧跑老远定义一个函数,然后使用的时候调用,也就是函数调用的地方和定义的地方太远,这降低了代码可读性。而Lambda表达式更灵活,即你可以就近定义并直接调用,当然了你也可以定义之后不调用等到用的时候调用。
1.Lambda表达式的语法。
2.Lambda表达式的定义与调用。
如上图, 635只是定义了fp。637才是调用。
638是定义并直接调用。并使用缺省参数。
同样的:
我们在定义了一个表达式但是并没有调用,那么尽管表达式明确写了会构建一个Int对象,但我们没有调用,那么这个表达式也不会构建。
3.推导返回值类型可以省略。
我们在647省略了->int,一来减少代码,二来可以让编译器自行推导。但要注意函数返回值不能出现歧义:
这显然是在为难编译器。
还有这种:
你是要推导为vector<int>呢?还是list<int>?还是.............
像上面这种就得自己明确定义返回值类型:
4.参数列表也是可以省略的。
Lambda表达式在没有参数时,参数列表也可以省略。
但是这样是不行的:
即:你省略了参数表却没有省略->int,这是不行的。要么你不要省略参数列表,把->int省略了;
要么两个都省略了。省略参数表,却不省略->int是不允许的;
5.捕获列表。
需要注意的是:全局变量不必捕获,直接使用即可,这与函数中使用全局变量是一样的。
按值捕获的时候,这些值都是不可修改的,它们具有常性。如果你非要修改请加mutable关键字。
正确写法:
按值捕获会有拷贝:
如上,我们使用mutable关键字得以修改a,但是你得记住,这个a是形参中的a的副本,它是拷贝来的,它和形参中的a是不同的变量。mutable只是让你拥有了修改按值捕获的变量的权限。你修改它不会影响我的形参a的值。同理,你捕获了对象也是一样的。
此外obj作为自定义类型对象且按值捕获,我们在调用Lambda时,Int的拷贝构造被调用。
但是你如果按值捕获`[=]` , 但你在函数体内并没有使用obj的话,也不会调用拷贝构造生成副本。
此外,你如果按值捕获`[=]`了一个对象数组,但在函数体内仅仅使用了偌大数组中的一个对象,那么起码在MSVC上,这个对象数组会被全部拷贝一份。所以我们应该尽可能减少按值捕获对象数组。开销太大。
与上面几乎差不多的代码,只是调用了两次表达式:
我们发现obj仅仅拷贝了一次,析构了一次。
如何理解?我们可以认为第一次拷贝来的obj对象和a变量是属于fp的,它随着fp的生存期结束而结束。这样,你第二次调用时,第一次拷贝的obj对象还在,a变量还在,那么a自然就等于2了。
通过调试我们也可以发现确实是这样:
自始至终,fp之下只有一个拷贝来的obj对象和a变量.
lambda表达式是向上捕获的,当然了全局变量不存在捕获。
如上,b定义在fp之下,那就无法捕获。
funa函数的表达式无法捕获funb函数的局部变量和对象。
如果使用了[&]或者[=],那么默认捕获当前类中的this指针,这样就可以操作成员函数和成员变量。
[this]捕获当前类中的this指针,这样我们可以调用这个对象(this指针指向的)的成员函数或者操作成员变量。
源码:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
class Int {
private:
int val;
public:
Int(int value) :val(value) {
cout << "构造函数 Int()" << endl;
}
~Int() { cout << "析构函数~Int() and value is " << val << endl; }
int& setValue(int v) {
val = v;
return val;
}
int getValue()const {
return val;
}
Int(const Int& other) :val(other.val) {
cout << "拷贝构造" << endl;
}
Int& operator=(const Int& other) {
if (this != &other) {
this->val = other.val;
}
cout << "赋值" << endl;
return *this;
}
Int& operator=(Int&& other) {
if (this != &other) {
val = other.val;
other.val = -1;
}
cout << "移动赋值" << endl;
return *this;
}
Int(Int&& it) :val(it.val) {
cout << "移动构造" << endl;
val = -1;
}
void fun(vector<int>& vec) {
for_each(vec.begin(), vec.end(), [this](int a) {
cout << "遍历到了" << a << "调用我的对象(obj)的私有变量val=" << val << endl;
});
}
};
int main() {
vector<int> vec{ 1,2,3,4,5 };
Int obj(0);
obj.fun(vec);
return 0;
}
上一篇: 无线网络基础
推荐阅读
-
Lambda 表达式
-
React (a) 认识 React,熟悉类组件、JSX 编写规范、嵌入式变量表达式、绑定属性 - 三种、JSX 语法
-
PostgreSQL洞察与知识汇总(一百五十三)|【性能】将OR子句转换为ANY表达式
-
Lua 正则表达式(模式匹配规则)--提取颜色/颜色代码
-
[ECMAScript 从入门到进阶教程] 第三部分:高级主题(高级函数和范例、元编程、正则表达式、性能优化)
-
华为仓颉语言入门(9):for-in 表达式
-
用于 MongoDB 的查询/超细节/表达式符号
-
正则表达式
-
2024 高二上 js 高级 + ES6 学习 9.29(深/浅拷贝、正则表达式、let/const、解构赋值、箭头函数、剩余参数)
-
kotlin 中的对象表达式与 Java 中的匿名内部类的比较