欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

Lambda 表达式

最编程 2024-10-14 20:47:35
...

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;
}