⭐上篇文章:42.C++11-右值引用与移动语义/完美转发_c++11中移动语义和完美转发的区别-CSDN博客

⭐本篇代码:c++-learning-of-yzc: c++/数据结构/算法的学习记录 (gitee.com)

目录

一. 什么是lambda表达式

1.1 lambda表达式的格式⭐

1.2 捕捉列表

二. lambda表达式使用举例

2.1 普通函数

2.2 作为可调用对象

三. lambda表达式的原理

四. 关于lambda表达式的拷贝问题


一. 什么是lambda表达式

lambda表达式的本质就是一个函数

1.1 lambda表达式的格式⭐

书写格式为:

[ capture-list ] ( parameters ) mutable -> return-type { statement} 

说明:

[ ] 内部的capture-list是捕捉列表:表示这个lambda需要捕捉的变量,捕捉的变量可以在lambda内部使用,捕捉方式分为 值捕捉 和 引用捕捉

() 内部的 paramenters 是参数列表,表示这个lambda的参数。简单来说就是函数的参数

mutable表示能够修改捕捉列表的值,为空表示不能修改。(这个只对值捕捉有影响,如果引用捕捉,无论有无mutable都能够修改)

-> return-type:指定这个lambda表达式的返回类型,即这个函数的返回类型

{}以及内部的statement,表示lambda表达式具体的代码,即这个函数的代码

1.2 捕捉列表

捕捉列表是lambda表达式相对于普通函数所独有的特性

lambda表达式可以捕捉外部变量进行访问和修改

捕捉方式如下: var表示要捕捉的变量

[var]         表示按值捕捉这个变量

[&var]       表示按引用捕捉这个变量

[=]            表示按值捕捉上文所有变量

[&]            表示按引用捕捉上文所有变量

[this]          类中可以捕获this

注意:

1 捕捉方式有传值捕捉,传引用捕捉。且传值捕捉的变量是无法改变的,只有加上了mutable才可以改变

2 父作用域指的是包含lambda表达式的语句块

3 捕捉列表可以由多个捕捉项构成,用逗号隔开。但是不允许重复捕捉,否则会编译错误

4 在块作用域意外的lambda表达式的捕捉列表必须为空

5 lambda表达式仅能捕捉父作用域中的变量,捕捉其他变量会编译出错

二. lambda表达式使用举例

2.1 普通函数

这里定义一个 add函数用于测试

#include <iostream>

int main()
{
    // 定义一个两数相加的lambda表达式
    auto add = [](int a, int b) -> int
    { return a + b; };

    int num1 = 1;
    int num2 = 2;
    std::cout << add(1, 2) << std::endl;
    return 0;
}

2.2 作为可调用对象

        STL中默认的sort是按升序排序的,可以通过自带的比较器greater,或者自定义比较函数,结构体对象来进行降序。

        更方便的方式是使用lambda表达式

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

void test()
{
    vector<int> arr;
    for (int i = 0; i < 10; i++)
    {
        arr.emplace_back(rand() % 10000);
    }

    cout << "排序前:";
    for (auto &e : arr)
        cout << e << " ";
    cout << endl;

    //使用lambda表达式作为函数对象
    sort(arr.begin(), arr.end(), [](const int &a, const int &b) -> int
         { return a > b; });

    cout << "排序后:";
    for (auto &e : arr)
        cout << e << " ";
    cout << endl;
}

int main()
{
    srand(time(0) ^ rand());
    test();
    return 0;
}

运行结果如下:

三. lambda表达式的原理

void test1()
{
    int a = 1, b = 2;
    auto add = [](const int& a, const int& b)->int {return a + b; };
    add(1, 2);
 
    /*
    00007FF6198BE4DE  mov    dword ptr[rbp + 144h], 2
    00007FF6198BE4E8  mov    dword ptr[rbp + 164h], 1
    00007FF6198BE4F2  lea    r8, [rbp + 144h]
    00007FF6198BE4F9  lea    rdx, [rbp + 164h]
    00007FF6198BE500  lea    rcx, [add]
    00007FF6198BE504  call   `test1'::`2': : <lambda_1>::operator() (07FF6198BC930h)
    */
}
 
int main()
{
    test1();
   
    return 0;
}

        通过汇编代码可以看到,lambda表达式本质是一个对象,底层是通过仿函数实现的,通过重载operator()来实现函数

四. 关于lambda表达式的拷贝问题

        思考一下, lambda表达式能否拷贝?

        lambda表达式是可以拷贝的!不过能否拷贝需要取决于这个lambda表达式的捕捉列表中的捕捉对象能否拷贝。

        如果捕捉对象可以拷贝,这个表达式就能够拷贝。如果捕捉的对象的拷贝是被私有了或者禁用了,这个lambda表达式就无法拷贝

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐