• C++11——lambda表达式


    在这里插入图片描述

    1. C++98对自定义类型的排序

    在C++98中,想要对自定义类型就行排序,我们得自己写仿函数来表明我们相对哪一项进行排序

    struct Student
    {
    	Student(string name, long id, double score)
    		:_name(name)
    		,_id(id)
    		,_score(score)
    	{}
    
    	string _name;
    	long _id;
    	double _score;
    };
    
    //按名字排序 -- 降序
    struct CmpName
    {
    	bool operator()(const Student& stu1, const Student& stu2)
    	{
    		return stu1._name < stu2._name;
    	}
    };
    //按学号排序 -- 降序
    struct CmpId
    {
    	bool operator()(const Student& stu1, const Student& stu2)
    	{
    		return stu1._id < stu2._id;
    	}
    };
    //按分数排序 -- 降序
    struct CmpScore
    {
    	bool operator()(const Student& stu1, const Student& stu2)
    	{
    		return stu1._score < stu2._score;
    	}
    };
    
    int main()
    {
    	vector<Student> v = { {"张三",101,99.3},{"李四",104,85.2},{"王五",102,99.9} };
    	sort(v.begin(), v.end(),CmpName());
    
    	sort(v.begin(), v.end(),CmpId());
    	
    	sort(v.begin(), v.end(),CmpScore());
    
    	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
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    如果代码风格较好,然后加上了注释,这其他人一看就懂是什么意思。但如果命名不规范,就是个很头疼的问题。

    例如:

    int main()
    {
    	vector<Student> v = { {"张三",101,99.3},{"李四",104,85.2},{"王五",102,99.9} };
    	sort(v.begin(), v.end(),Cmp1());
    
    	sort(v.begin(), v.end(),Cmp2());
    	
    	sort(v.begin(), v.end(),Cmp3());
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    这里的仿函数,我们看到就不知道是对哪一项进行排序,就得往前翻,如果前面的命名也不规范,那就十分痛苦。

    而且一旦我们的对象的参数多了,那我们就得写出对应的仿函数,这不是很方便,于是在C++11中出现了lambda表达式

    2. lambda表达式语法

    lambda表达式格式[capture-list] (parameters) mutable -> return-type { statement }

    示例:[] (int x,int y)->int { return x+y;}

    • lambda表达式各部分说明

      []:捕捉列表,该列表总是出现在lambda函数的开始位置,编译器根据[]来 判断接下来的代码是否为lambda函数,捕捉列表能够捕捉上下文中的变量供lambda函数使用。

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

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

      ->returntype:返回值类型。用追踪返回类型形式声明函数的返回值类型,没有返回值时此部分可省略返回值类型明确情况下,也可省略,由编译器对返回类型进行推导

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

    int main()
    {
    	vector<Student> v = { {"张三",101,99.3},{"李四",104,85.2},{"王五",102,99.9} };
    	sort(v.begin(), v.end(), [](const Student& stu1, const Student& stu2)->bool {return stu1._name < stu2._name; });
    
    	sort(v.begin(), v.end(), [](const Student& stu1, const Student& stu2)->bool {return stu1._id < stu2._id; });
    	
    	sort(v.begin(), v.end(), [](const Student& stu1, const Student& stu2)->bool {return stu1._score < stu2._score; });
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2.1 捕捉列表

    • [var]:表示值传递方式捕捉变量var

      int a = 1;
      int b = 2;
      double rate = 2.5;
      auto f1 = [rate](int x, int y) {return x + y; };
      cout<<f1(a,b)<<endl;	//输出 7.5
      
      • 1
      • 2
      • 3
      • 4
      • 5
    • [&var]:表示引用传递捕捉变量var

      适用于对象较大或者需要修改捕捉列表里面的值

      int a = 1;
      int b = 2;
      auto swap1 = [a, b]() mutable {
          //mutable让捕捉的a b可以修改
          //但这里面的a b 属于是外面a b的拷贝
          int tmp = a;
          a = b;
          b = tmp;
      };
      swap1();
      
      
      auto swap2 = [&a, &b] {
          //捕捉引用,可以直接修改外面a b的值了
          int tmp = a;
          a = b;
          b = tmp;
      };
      swap2();
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
    • [=]:表示值传递方式捕获所有父作用域中的变量(包括this)

      捕捉所有的外部变量

      int a = 1;
      int b = 2;
      int c = 3;
      auto f2 = [=]() {
          cout << a << " " << b << " " << c << " " << endl;
      };
      f2();
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
    • [&]:表示引用传递捕捉所有父作用域中的变量(包括this)

      捕捉所有外部变量的引用

      int a = 1;
      int b = 2;
      int c = 3;	
      auto f3 = [&]() {
      cout << ++a << " " << ++b << " " << ++c << " " << endl;
      };
      f3();
      cout << a << " " << b << " " << c << " " << endl;
      //也可以混合捕捉,这里的a就是不可修改的了,普通捕捉
      auto f4 = [&, a] {
      cout << a << " " << ++b << " " << ++c << " " << endl;
      };
      cout << a << " " << b << " " << c << " " << endl;
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
    • [this]:表示值传递方式捕捉当前的this指针

    3. lambda底层原理

    int main()
    {
    	auto f1 = [](int x, int y) {return x + y; };
    	auto f2 = [](int x, int y) {return x + y; };
    	//f1 = f2;	//error
    	cout << typeid(f1).name() << endl;
    	cout << typeid(f2).name() << endl;
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    这段代码运行之后发现,f1f2的类型是

    image-20231018120622477

    这里lambda的底层就是一个仿函数,就和范围的for的底层就是迭代器一样,上层将其封装了,调用的就是类的operator()

    image-20231018121051482

  • 相关阅读:
    145. 二叉树的后序遍历
    SpringBoot2.x拥抱本地缓存之王Caffeine
    67-Java面向对象三大特征之三:多态
    【附代码案例】深入理解 PyTorch 张量:叶子张量与非叶子张量
    学习太极创客 — MQTT 第二章(九)本章测试
    E. Singhal and Numbers(质因数分解)
    【无标题】
    macOS 运行xxx.command文件提示”无法执行,因为您没有正确的访问权限“解决方法
    一种对中定位夹具的机构设计
    Google App Campaigns的逻辑及其建议
  • 原文地址:https://blog.csdn.net/Dirty_artist/article/details/133903530