• 【C++】C++11——lambda表达式


    lambda表达式是一个匿名函数,即他没有函数名,使用lambda表达式可以使代码更为简洁易懂,提高了代码的可读性

    lambda表达式语法

    lambda表达式书写格式:[捕捉列表](参数列表)mutable->返回值类型{函数体}

    • 捕捉列表编译器根据[] 来判断接下来的代码是否为lambda函数,捕捉列表能够捕捉上下文红的变量供lambda函数使用。
      - [](){}空捕获列表,不捕获任何外部变量
      - [变量名](){}值捕获,通过拷贝方式捕获外部变量,并在lambda函数体内使用其拷贝
      - [&变量名](){}引用捕获,通过引用方式捕获外部变量,并在lambda函数体内共享其引用
      - [=](){}隐式捕获,省略捕获列表的变量,编译器将根据变量自动判断是否按值或引用捕获
      - [&](){}引用捕获,使任何外部变量按引用捕获,除非显示指定为值捕获
      - [=, &intVar](){}:使用任何外部变量按值捕获,除了intVar是按引用捕获的。

    • 参数列表:与普通函数的参数列表一致,如果不需要参数传递,则可以联通()一起省略。

    • mutable:默认情况下,lambda函数总是一个const函数,mutable可以取消其常量性。使用该修饰符时,参数列表不可以省略。(即使参数列表为空)

    • ->返回值类型:这部分也可以省略,当返回值明确的时候,编译器会自己推断,但是一般加上为好

    • 函数体:在该函数体内,除了可以使用其参数外,还可以使用所有捕获到的变量。

    使用lambda创建函数

    int main()
    {
    	int a = 1, b = 2;
    	auto sw = [](int &x, int &y)->void
    	{
    		int tmp = x;
    		x = y;
    		y = tmp;
    	};
    	sw(a, b);
    	cout << "a:" << a << "     " << "b:" << b << endl;
    
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在这里插入图片描述

    • lambda表达式是一个匿名函数,该函数无法直接调用,如果想要直接调用,可借助auto将其赋值给一个变量,此时这个变量就可以像普通函数一样使用。

    利用捕捉列表捕捉

    在这里插入图片描述
    这样一来,调用lambda表达式时就不用传入参数了,但实际我们只需要用到变量a和变量b,没有必要把父作用域中的所有变量都进行捕捉,因此也可以只对父作用域中的a、b变量进行捕捉。比如:
    在这里插入图片描述
    说明一下: 实际当我们以[&]或[=]的方式捕获变量时,编译器也不一定会把父作用域中所有的变量捕获进来,编译器可能只会对lambda表达式中用到的变量进行捕获,没有必要把用不到的变量也捕获进来,这个主要看编译器的具体实现。

    lambda的底层实现原理

    实际lambda底层实现使用的其实就是我们平时的仿函数类型,它的字节大小为一个字节,也就是说,lambda占的空间大小为1个字节

    他和普通的仿函数一样,他们都是通过重载的()来进行调用的。

    下面,我们来自定义实现一个仿函数和调用lambda查看一下他们的区别

    class Add
    {
    public:
    	Add(int base)
    		:_base(base)
    	{}
    	int operator()(int num)
    	{
    		return _base + num;
    	}
    private:
    	int _base;
    };
    int main()
    {
    	int base = 1;
    
    	//函数对象
    	Add add1(base);
    	add1(1000);
    
    	//lambda表达式
    	auto add2 = [base](int num)->int
    	{
    		return base + num;
    	};
    	add2(1000);
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    调试代码并转到反汇编,可以看到:

    • 在创建函数对象add1时,会调用Add类的构造函数。
    • 在使用函数对象add1时,会调用Add类的()运算符重载函数。
      在这里插入图片描述

    当调用lambda时

    • 借助auto将lambda表达式赋值给add2对象时,会调用类的构造函数。
    • 在使用add2对象时,会调用类的()运算符重载函数。

    在这里插入图片描述
    lambda他们之间是不可以相互赋值的,尽管他们实现的函数逻辑是一样的也不可以
    其根本原因就是我们使用lambda时,该函数调用的类名为

    • 类名中的uuid叫做通用唯一识别码(Universally Unique Identifier),简单来说,uuid就是通过算法生成一串字符串,保证在当前程序当中每次生成的uuid都不会重复。
    • lambda表达式底层的类名包含uuid,这样就能保证每个lambda表达式底层类名都是唯一的。
  • 相关阅读:
    Vue组件化编码流程,组件自定义事件,全局事件总线,消息订阅与发布
    LevitasBio补强公司高级管理层
    第五十章 开发自定义标签 - 使用Rule类
    【AT32】雅特力固件库开发入门(视频连载中)
    安装最新版React devtool
    非技术部门,如何参与 DevOps?
    统计信号处理基础 习题解答6-14
    进程
    非零基础自学Golang 2 开发环境 2.5 第一个Go 程序
    JAVA毕业设计购物网站设计计算机源码+lw文档+系统+调试部署+数据库
  • 原文地址:https://blog.csdn.net/wh9109/article/details/133197231