• C++11新增特性lambda表达式


    前言

    C++98中的一个例子。

    #include 
    #include 
    #include 
    #include 
    using namespace std;
    
    struct Goods
    {
    	string _name;
    	float _price;
    	int _evaluate;
    	Goods(const char* str, double price, int evaluate)
    		:_name(str)
    		, _price(price)
    		, _evaluate(evaluate)
    	{}
    };
    
    struct PriceGreater
    {
    	bool operator()(const Goods& g1, const Goods& g2)
    	{
    		return g1._price < g2._price;
    	}
    };
    struct PriceLess
    {
    	bool operator()(const Goods& g1, const Goods& g2)
    	{
    		return g1._price > g2._price;
    	}
    };
    int main(void)
    {
    	vector<Goods> v{ {"苹果", 3.15, 5}, {"香蕉", 4.2, 3}, {"西瓜", 2.8, 4} };
    	sort(v.begin(), v.end(), PriceLess()); //按价格的降序比较
    	sort(v.begin(), v.end(), PriceGreater()); //按价格的升序比较
    	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
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    如果待排序的元素是自定义类型,使用sort算法排序时,需要用户去定义仿函数类。如果每次比较逻辑不同,就需要实现不同仿函数类,这是极其不方便的。所以c++11语法增加了Lambda表达式。

    lambda表达式格式

    lambda表达式的格式

    [捕捉列表](参数列表)mutable->返回值类型{ 语句部分 };

    其中参数列表、返回值类型是可选的,捕捉列表、函数体可以为空。
    先来看一个较为简单的lamda表达式

    int main(void)
    {
    	auto add = [](int a, int b)->int {return a + b; };
    
    	cout << add(1, 2) << endl;
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    mutable可以省略,暂时不考虑。

    • 捕捉列表,捕捉列表的[]是千万不能省略的,编译器会根据[]判断该表达式是否为lambda表达式,捕捉列表能够捕捉上下文的变量提供给lambda表达式使用。
    • 参数列表,就和普通的函数传参是一样的,如果不需要参数,那么可以连同()一起省略
    • mutable:默认情况下,lambda表达式参数列表和捕捉列表被修饰成const属性,而mutable的作用就是取消它的const属性。如果使用了mutable参数一定不能省略,如果参数为空,那么需要保留()
    • ->返回值类型。返回值类型明确或没有返回值的情况下,该部分可省略,编译器会对返回值类型进行推导。
    • 语句部分。和不同函数的函数体内语句部分是一样的含义,函数体内不仅可以使用它的参数,还可以使用所有捕获到的变量。

    所以最简单的lambda表达式应该是[]{}
    lambda表达式又被称为匿名函数,无法被直接调用,它的底层其实也是仿函数类。需要借助auto将表达式赋值给一个变量。

    一些语法

    lambda表达式的捕捉列表不能捕捉全局变量/静态变量

    //lambda表达式的捕捉列表不能捕捉全局变量 / 静态变量
    int c = 0, d = 0;
    auto func1 = [c, d]() {};
    
    int main(void)
    {
    	static int a = 0;
    	static int b = 0;
    	auto func1 = [a, b]() {};
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    如果想要改变参数/捕捉列表,那么就需要加mutable取消const 属性

    //交换两个变量的值,方式一:
    	int a = 1, b = 2;
    	auto swap1 = [](int& x, int& y)mutable {int tmp = x; x = y; y = tmp; };
    	swap1(a, b);
    
    • 1
    • 2
    • 3
    • 4

    捕捉列表描述了上下文中那些数据可以被lambda使用,以及使用的方式传值还是传引用。
    [var]:表示值传递方式捕捉变量var
    [=]:表示值传递方式捕获所有父作用域中的变量(包括this)
    [&var]:表示引用传递捕捉变量var
    [&]:表示引用传递捕捉所有父作用域中的变量(包括this)
    [this]:表示值传递方式捕捉当前的this指

    默认情况下,使用值传递的方式,捕捉到的变量被修饰成const属性;引用传递方式没有被修饰。
    函数体内使用捕捉到变量,实际上是捕捉变量的一份拷贝,所以需要对捕捉变量进行修改时,不能使用值传递的方式。

    //交换两个变量的值,方式二:
    	auto swap3 = [&c, &d](){int tmp = c; c = d; d = tmp; };
    	swap3();
    
    • 1
    • 2
    • 3

    【捕捉列表注意】
    同一个变量不能被同一种传递方式多次捕捉。捕捉的范围:父作用域中所有的非静态局部变量。
    在这里插入图片描述
    在这里插入图片描述

    走进底层

    调用lambda表达式的时候,先把它赋值给auto类型的对象,然后再使用()调用。
    auto的作用是自动推导右边表达式的类型,那么lambda表达式的类型是什么?
    在这里插入图片描述
    add是一个类对象,类名为,点击此处了解uuid

    增加一个lambda表达式的调用
    add(1, 2);
    
    • 1
    • 2

    转到反汇编,发现它的类里重载了(),调用lambda表达式的底层是去调用类成员方法operator()
    在这里插入图片描述
    可见lambda表达式的底层就是仿函数类,所以它的调用方法也和仿函数是一样的。

    不同的lambda表达式生成的类,是不同的类。一个lambda表达式再写一份,生成的类也是不同的,可以认为一个lambda表达式语句生成一个自己唯一的类。

    	//lambda表达式格式
    	auto add = [](int a, int b)->int {return a + b; };
    	add(1, 2);
    	auto add2 = [](int a, int b)->int {return a + b; };
    	add2(1, 2);
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述
    因此要注意,lambda表达式之间不能相互赋值。

  • 相关阅读:
    并发的三大特性
    Python零基础入门-11 标准库简介 —— 第二部分
    GPT与创作:革命性的合作还是失业的噩梦?
    Zookeeper 集群搭建
    JAVA计算机毕业设计宠物销售管理系统Mybatis+系统+数据库+调试部署
    elementUI选择框,value为0时无法获取的问题以及解决办法
    spring redis工具类
    leetcode-数组系列算法总结
    华为机试 - 目录删除
    【C语言步行梯】一维数组、二维数组介绍与应用详谈
  • 原文地址:https://blog.csdn.net/qq_56870066/article/details/126386242