C++11——lambda表达式

article/2025/10/4 0:49:11

目录

前言

一.lambda表达式用法

二.lambda表达式语法

 三.lambda表达式的原理


前言

        在显示生活中,我们在用手机购物时。总是可以在页面上看到下面这样的选项。

        我们知道底层这是通过排序来完成的,但是当我们实现时,要写多个排序算法,写多个仿函数来实现不同变量的比较。

比如下面代码:

struct CompareNameSmall;
struct CompareNameBig;
struct ComparePriceSmall;
struct ComparePriceBig;class Goods{friend struct CompareNameSmall;friend struct CompareNameBig;friend struct ComparePriceSmall;friend struct ComparePriceBig;private:string _name;double _price;
public:Goods(string name, double price):_name(name),_price(price){}};//仿函数
struct CompareNameSmall{bool operator()(const Goods& g1, const Goods& g2){return g1._name < g2._name;}
};
struct CompareNameBig{bool operator()(const Goods& g1, const Goods& g2){return g1._name > g2._name;}
};
struct ComparePriceSmall{bool operator()(const Goods& g1, const Goods& g2){return g1._price < g2._price;}
};
struct ComparePriceBig{bool operator()(const Goods& g1, const Goods& g2){return g1._price > g2._price;}
};int main(){Goods gds[] = { { "苹果", 2.5 }, { "香蕉", 3.0 }, { "梨", 3.5 } };sort(gds, gds + (sizeof(gds) / sizeof(gds[0])), CompareNameSmall());sort(gds, gds + (sizeof(gds) / sizeof(gds[0])), CompareNameBig());sort(gds, gds + (sizeof(gds) / sizeof(gds[0])), ComparePriceSmall());sort(gds, gds + (sizeof(gds) / sizeof(gds[0])), ComparePriceBig());system("pause");return 0;
}

随着C++的发展,人们开始觉得上面的写法太复杂了。每次为了实现一个比较算法,都需要重新定义一个类,如果每次的比较逻辑不一样,还要实现多个类,特别是在相同类的命名上。并且如果不能达到见名知义,我们还得去找对应的仿函数,才能知道它的功能,这给编程者带来了极大的不便。

        因此在C++11语法中出现了lambda表达式。

一.lambda表达式用法

class Goods{public:string _name;double _price;Goods(string name, double price):_name(name), _price(price){}};int main(){Goods gds[] = { { "苹果", 2.5 }, { "香蕉", 3.0 }, { "梨", 3.5 } };//使用lambda表达式sort(gds, gds + (sizeof(gds) / sizeof(gds[0])), [](const Goods& g1, const Goods& g2)->bool{return g1._name < g2._name; });sort(gds, gds + (sizeof(gds) / sizeof(gds[0])), [](const Goods& g1, const Goods& g2)->bool{return g1._name > g2._name; });sort(gds, gds + (sizeof(gds) / sizeof(gds[0])), [](const Goods& g1, const Goods& g2)->bool{return g1._price < g2._price; });sort(gds, gds + (sizeof(gds) / sizeof(gds[0])), [](const Goods& g1, const Goods& g2)->bool{return g1._price > g2._price; });system("pause");return 0;
}

 可以实现和上面一样的效果。虽然一样要写这么多函数,但是不需要面临去定义很多类和命名问题,并且不需要在去找函数。

但是我们发现lambda表达式的格式还是很奇怪的,下面来介绍一下lambda表达式的写法。

二.lambda表达式语法

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

  • [捕捉列表]:该列表总是出现在lambda表达式的起始位置,编译器根据[]来判断接下来的代码是否为lambda表达式,捕捉列表能够捕捉当前作用域中的变量,供lambda函数使用。
    • [val]:表示以传值方式捕捉变量val
    • [=]:表示以传值方式捕捉当前作用域中的变量,包括this指针。
    • [&val]:表示以引用方式传递捕捉变量val。
    • [&]:表示以引用方式传递捕捉当前作用域中的所有变量,包括this指针。
    • [this]:表示以传值方式捕捉当前的this指针。
  • (参数):参数列表。与普通函数参数列表使用相同。如果不需要传递参数,可以连同"()"一起省略。
  • mutable:默认情况下,lambda函数总是一个const函数,捕捉的传值参数具有常性,mutable可以取消常性。使用mutable修饰符时,参数列表不能省略,即使参数为空。
  • —>返回值类型:返回值类型。使用追踪返回类型形式声明函数的返回值类型,没有返回值此部分可省略。返回值类型明确的情况下,也可省略,由编译器推导。
  • {函数体}:在函数体内除了可以使用参数外,还能使用捕捉的变量。

注意:在lambda表达式中,参数列表和返回值类型都可省略,而捕捉列表和函数体可以为空。所以最简单的lambda表达式为:[]{},该表达式不能做任何事。

int main(){//最简单的lambda表达式[]{};//捕捉当前作用域的变量,没有参数,编译器推导返回值类型。int a = 1;int b = 2;[=]{return a + b; };//使用和仿函数差不多auto fun1 = [&](int c){b = a + c; };fun1(10);cout << a << " " << b << endl;auto fun2 = [&](int c)->int{return a + c; };fun2(20);cout << fun2(20) << endl;//传值捕捉int x = 1;int y = 2;auto add0 = [x, y]()mutable->int{ x *= 2;//捕捉传递传值具有常性return x + y; };cout << add0() << endl;auto add1 = [&x, y]()->int{ x *= 2;//捕捉传递引用不具有常性return x + y; };cout << add1() << endl;auto add2 = [](int s, int m)->int{ s *= 2;//参数不具有常性return s + m; };system("pause");return 0;
}

        从上面要注意的一点是:捕捉列表传值传递具有常性,要加mutable,传引用传递不具有常性,参数列表不具有常性。

捕捉列表的要和捕捉参数变量名相同,传值传递是当前作用域变量的拷贝。

int main(){//最简单的lambda表达式[]{};//捕捉当前作用域的变量,没有参数,编译器推导返回值类型。int a = 1;int b = 2;//auto fun1 = [x, y]()->int{return x + y; };//编译错误,要和捕捉参数名相同//传值传递是捕捉变量的拷贝,实际外面的a,b没有交换auto swap1 = [a, b]()mutable{int z = a; a = b; b = z; };swap1();//注意还需要调用cout << a << " " << b << endl;//传引用才能真正修改auto swap2 = [&a, &b]{int z = a; a = b; b = z; };swap2();cout << a << " " << b << endl;return 0;
}

 注意构造完对象后,对象调用,函数才起作用。

注意点:

  • 语法上捕捉列表可由多个捕捉项组成,并以逗号隔开。捕捉项不能重复传递,否则会导致编译错误。比如:当前作用域已经有了变量a,捕捉设为[=,a],=已经捕捉过a了,编译时会报错。
  • 捕捉列表只能捕捉当前作用域的局部变量,作用域以外的局部变量或者非局部变量都会报错。
  • lambda表达式之间不能赋值,即使看起来类型相同。
void (*PF)();
int main(){auto f1 = []{cout << "hello world" << endl; };auto f2 = []{cout << "hello world" << endl; };// 此处先不解释原因,等lambda表达式底层实现原理看完后,大家就清楚了//f1 = f2; // 编译失败--->提示找不到operator=()// 允许使用一个lambda表达式拷贝构造一个新的副本auto f3(f2);f3();// 可以将lambda表达式赋值给相同类型的函数指针PF = f2;PF();return 0;}

 三.lambda表达式的原理

        首先我们先来比较一下仿函数和lambda表达式

        我们发现仿函数的使用和lambda表达式差不多。

class Rate
{
public:Rate(double rate) : _rate(rate){}double operator()(double money, int year){return money * _rate * year;}
private:double _rate;
};
int main()
{// 函数对象double rate = 0.49;Rate r1(rate);r1(10000, 2);// lamberauto r2 = [=](double monty, int year)->double{return monty*rate*year; };r2(10000, 2);return 0;
}

         通过汇编来查看lambda表达式部分:

        lambda表达式原理:实际编译器在全局作用域自动生成了一个类,在类中重载了operator(), operator()函数的内容就是lambda表达式的内容。

        可以理解成lambda表达式底层还是仿函数。本来时要程序员编写,现在变成了编译器自动生成,我们看起来跟方便了。

 


http://chatgpt.dhexx.cn/article/XuntggrD.shtml

相关文章

C++ lambda 表达式深剖

目录 传统艺能&#x1f60e;概念&#x1f914;语法&#x1f914;捕获方式&#x1f914;相互赋值&#x1f60e; mutable&#x1f914;底层原理&#x1f914; 传统艺能&#x1f60e; 小编是双非本科大一菜鸟不赘述&#xff0c;欢迎米娜桑来指点江山哦&#xff08;QQ&#xff1a;…

Lambda表达式的本质

一直想写一篇文章&#xff0c;来总结lambda表达式&#xff0c;但是之前感觉总结的不是特别到位&#xff0c;现在看了几篇文章和视频后&#xff0c;感觉对lambda表达式有了比较深刻的认识&#xff0c;现在进行记录总结如下&#xff1a; lambda表达式又叫做匿名函数&#xff0c;…

Java Lambda 表达式

目录 一、说明二、理解三、演示1.常规方法实现2.静态内部类3.局部内部类4.匿名内部类5.Lambda表达式6.Lambda再简化 一、说明 Lambda表达式是什么 Lambda 表达式也称为闭包&#xff0c;是Java 8 发布的新特性Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中) …

C++ Lambda表达式

在C11和更高版本中&#xff0c;Lambda表达式&#xff08;通常称为Lambda&#xff09;是一种在被调用的位置或作为参数传递给函数的位置定义匿名函数对象&#xff08;闭包&#xff09;的简便方法。Lambda通常用于封装传递给算法或异步函数的少量代码行。1 Lambda表达式是C11中一…

java Lambda表达式详解

文章目录 一、背景1.1语法1.2函数式接口 二、Lambda的基本使用2.1引子2.2常见的使用方式2.3语法小结 三、变量捕获3.1 匿名内部类3.2 匿名内部类的变量捕获3.3Lambda的变量捕获 四、Lambda在集合当中的使用4.1 Collection接口4.2 list接口4.3 Map接口 总结 提示&#xff1a;以下…

Lambda表达式详解

Lambda表达式 1. 为什么使用lambda表达式2. 入门案例3. lambda表达式组成4. lambda表达式使用4.1 语法格式一4.2 语法格式二4.3 语法格式三4.4 语法格式四4.5 语法格式五4.6 语法格式六 5. 总结 1. 为什么使用lambda表达式 lambda是一个匿名函数&#xff0c;我们可以吧lambda表…

Lambda 表达式

一.什么事Lambda表达式 Lambda 表达式是一种匿名函数&#xff0c;也可称为闭包&#xff0c;简单地说&#xff0c;它是没有声明的方法&#xff0c;也即没有访问修饰符、返回值声明和名字。 它可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格&#xff0c;使 Java 语言…

Lambda表达式超详细总结(简单易懂)

文章目录 1、什么是Lambda表达式2、为什么使用Lambda表达式3、函数式接口&#xff08;lambda表达式的使用前提&#xff09;4、推导Lambda表达式5、Lambda表达式语法 1、什么是Lambda表达式 Lambda表达式&#xff0c;也可称为闭包。其本质属于函数式编程的概念&#xff0c;是Ja…

Lambda表达式超详细总结

文章目录 1. 什么是Lambda表达式2. 为什么使用Lambda表达式3. Lambda表达式语法4. 函数式接口4.1 什么是函数式接口4.2 自定义函数式接口4.3 Java内置函数式接口 5. 方法引用6. 构造器引用7. 数组引用8. Lambda表达式的作用域8.1 访问局部变量8.2 访问局部引用&#xff0c;静态…

SQL语句学习之SQL基础的表创建以及添加数据

SQL语句学习之SQL基础的表创建以及添加数据 学习目标1&#xff1a; 一周内掌握SQL基础语句 tip:主要是在牛客网&#xff08;牛客网&#xff09;上进行练习&#xff0c;里面有在线编程&#xff0c;可以直接运行&#xff0c;而且有解题的思路&#xff0c;比较清晰&#xff0c;而…

Hive SQL之表与建表

Hive数据模型总览 用户通过数据库访问Hive后&#xff0c;首先选择哪个数据库&#xff0c;然后在库的下面选择的是一张张表&#xff0c;表是管理数据的的最基本的所在&#xff0c;在表中的一行行记录&#xff0c;在现实中就是一条条数据&#xff0c;里面有我们的字段字段类型和它…

SQLite 创建表SQL语句

SQLite 创建表 创表语法 CREATE TABLE [表名称](--主键列不可为空[列1] [类型] PRIMARY KEY NOT NULL,--列可为空[列2] [类型],--列不可为空[列3] [类型] NOT NULL );创表示例 CREATE TABLE User (Id INT PRIMARY KEY NOT NULL,Name Text,Sex INT NOT NULL )在线Sqlite查看器…

SQL创建表为啥不显示

这里新建表 左上角报存 保存完以后点击刷新就会出来刚创建的表格

SQL 创建表的备份

1. SELECT INTO 语句 SELECT INTO 语句从一个表中选取数据&#xff0c;然后把数据插入另一个表中。 SELECT INTO 语句常用于创建表的备份复件或者用于对记录进行存档&#xff1b; SQL SELECT INTO 语法 您可以把所有的列插入新表&#xff1a; SELECT * INTO new_table_name…

SQL Server创建表

我们要怎么在数据库中创建表呢&#xff01;首先&#xff0c;表在数据库和模式中唯一命名。每个表包含一个或多个列。 每列都有一个相关的数据类型&#xff0c;用于定义它可以存储的数据类型&#xff0c;例如&#xff1a;数字&#xff0c;字符串和日期。 要创建新表&#xff0c;…

SQL Server 创建表

我们在上一节中完成了数据库的创建&#xff0c;在本节&#xff0c;我们要往这个新的数据库中加入点数据&#xff0c;要想将数据添加到数据库&#xff0c;我们就必须在数据库中添加一个表&#xff0c;接下来来看看具体的操作。 我们的数据库是一个任务跟踪数据库&#xff0c;那…

ORACLE SQL 创建表

1.创建表&#xff1a; 1.1表名和列名&#xff1a; 一定要以字母开头 一定在 1-30 个字符之间 只能包含 A–Z, a–z, 0–9, _, $, 和 # 一定不能和用户定义的其他对象重名 一定不能是Oracle 的保留字 一定要有CREATE TABLE权限 而且需要一定的存储空间 还要指定的&…

利用SQL创建表结构

一、创建图书管理系统&#xff0c;其中涉及到的对象有&#xff08;图书分类&#xff0c;图书&#xff0c;学生&#xff0c;借书记录&#xff09; 1、列出关系模式 (1) 书本类别&#xff08;种类编号&#xff0c;种类名称&#xff09; (2) 学生&#xff08;学生编号&#xff0…

SQL创建表

要创建新的表&#xff0c;就要使用create table语句。 1、第一&#xff0c;要指定数据库的名称&#xff0c;必须是数据库有的&#xff0c;如果没有指定&#xff0c;那就默认是当前数据库。&#xff08;如图下所示是没有指定数据库的&#xff09; 2、第二&#xff0c;指定表的模…

SQL表的创建

一&#xff0c;创建表 1.使用普通方法创建表 1&#xff0c;进入SQL进行连接 2&#xff0c;在左边会有一个对象资源管理器&#xff0c;右键数据库&#xff0c;在弹出的窗口中选择新建数据库 3&#xff0c;给这个包取个名字&#xff0c;在这个界面可以给这个表选择存储地方&…