当前位置: 首页 > news >正文

C++——C++11(3)

C++——C++11(3)

  • lambda表达式(匿名的仿函数对象)
  • 一些注意点
    • lambda捕捉列表
      • [=]
      • [&]
      • [this]
    • lambda的赋值
  • function包装器
    • function成员函数的包装
  • bind绑定参数

我们今天接着来了解一下C++11一些新的特性,如果还没有看过上两次的小伙伴可以点击这里:

https://blog.csdn.net/qq_67693066/article/details/136577386
https://blog.csdn.net/qq_67693066/article/details/136658325

lambda表达式(匿名的仿函数对象)

后期,C++受到了其他语言的影响,风格开始发生了变化,这个lambda表达式就是受了其他语言的影响:

在C++中,lambda表达式(也称为匿名函数)提供了一种方便的方式来定义和使用内联的小函数对象。Lambda表达式特别适用于需要临时函数对象的情况,例如在算法调用(如std::sort、std::find_if等)中作为参数传递。

C++中的lambda表达式的基本语法如下:

[capture](parameters) -> return_type { body_of_lambda }

capture:捕获子句,用于捕获外部作用域的变量,以在lambda函数体内使用。可以是值捕获(通过=)或引用捕获(通过&)。也可以显式列出要捕获的变量。
parameters:lambda函数的参数列表,与常规函数参数列表类似。
return_type:返回类型,通常可以省略,编译器会自动推导返回类型。
body_of_lambda:lambda函数的主体,包含要执行的代码。
注意
在lambda函数定义中,参数列表和返回值类型都是可选部分,而捕捉列表和函数体可以为空。因此C++11中最简单的lambda函数为:[]{}; 该lambda函数不能做任何事情。

比如我可以用lambda表达式写一个简单的判断偶数的式子:

int main()
{vector<int> v1 = {1,2,3,4,5,6,7,8,9,10};auto s1 = [v1](int n){ //捕捉v1,参数为nif( n % 2 == 0){cout<<n<<"是偶数"<<endl; //body_of_lambda}};for(auto e : v1){s1(e); //调用s1}
}

在这里插入图片描述
我们可以看看s1的类型:

cout << typeid(s1).name() << endl;

在这里插入图片描述
这里class <lambda_741bc9d219826239a4505f712752848a>后面的这串字符串是uuid(通用唯一识别码)然后编译器会生成这么一个类型的仿函数:

我们打个断点,进入到反汇编:
在这里插入图片描述在这里插入图片描述在这里插入图片描述
我们可以通过lambda表达式实现自定义排序:
之前在C++98中如果我们要自定义排序,通常要写一个仿函数:

struct Goods
{string _name;  // 名字double _price; // 价格int _evaluate; // 评价Goods(const char* str, double price, int evaluate):_name(str), _price(price), _evaluate(evaluate){}
};struct ComparePriceLess
{bool operator()(const Goods& gl, const Goods& gr){return gl._price < gr._price;}
};struct ComparePriceGreater
{bool operator()(const Goods& gl, const Goods& gr){return gl._price > gr._price;}
};int main() {vector <Goods> v = {{"苹果", 2.1, 5},{"香蕉", 3,4},{"橙子", 2.2,3},{"菠萝", 1.5, 4}};sort(v.begin(), v.end(), ComparePriceGreater()); //使用ComparePriceGreater()匿名对象for(auto e: v){cout<<e._name << ": " <<e._price <<endl;}sort(v.begin(), v.end(), ComparePriceLess());cout << endl;for (auto e : v){cout << e._name << ": " << e._price << endl;}
}

现在我们有lambda匿名仿函数对象,我们就可以不用写这么多的仿函数了:

    sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2){return g1._price > g2._price; });for (auto e : v){cout << e._name << ": " << e._price << endl;}sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2){return g1._price < g2._price; }); cout << endl;for (auto e : v){cout << e._name << ": " << e._price << endl;}
}

在这里插入图片描述

一些注意点

既然我们可以通过lambda实现一些仿函数的功能,那么我们可以用这个实现一个简单的交换两个变量值的功能:

int main()
{int x = 10;int y = 19;cout << x << " " << y << endl;//使用lambda表达式auto s1 = [x, y]() {int temp;temp = x;x = y;y = temp;};

但是这样会报错:
在这里插入图片描述

在这里插入图片描述
那是因为:默认情况下,lambda函数总是一个const函数,mutable可以取消其常量性。使用该修饰符时,参数列表不可省略(即使参数为空)。
在这里插入图片描述
这下就可以了:

int main()
{int x = 10;int y = 19;cout << x << " " << y << endl;//使用lambda表达式auto s1 = [x, y]() mutable{int temp;temp = x;x = y;y = temp;};cout << endl;s1();cout << x << " " << y << endl;
}

这里我们的s1没有传参,是因为捕获列表[],捕捉到了上面的x,y{}函数体直接使用的是x和y:

我们来运行一下:
在这里插入图片描述发现这里并没有实现交换,估计多半是传的临时对象,我们可以传引用:
在这里插入图片描述
在这里插入图片描述
不仅这样,lambda的捕捉列表给了几种方式:

lambda捕捉列表

[var]:表示值传递方式捕捉变量var
[=]:表示值传递方式捕获所有父作用域中的变量(包括this)
[&var]:表示引用传递捕捉变量var
[&]:表示引用传递捕捉所有父作用域中的变量(包括this)
[this]:表示值传递方式捕捉当前的this指针

我们来看看[=]和[&],[this]的玩法:

[=]

[=]:表示值传递方式捕获所有父作用域中的变量(包括this)

int main()
{int x = 10;int y = 90;//lambda表达式 x属于外部变量auto lambda = [=]()mutable {x += 90;y += 90;cout << x << " " << y << endl;};lambda();cout << endl;//查看数值是否被修改cout << x << " " << y << endl;
}

在这里插入图片描述
发现原本的数值没有改变。

[&]

[=]:表示值传递方式捕获所有父作用域中的变量(包括this)

int main()
{int x = 10;int y = 90;//lambda表达式 x属于外部变量auto lambda = [&]() {x += 90;y += 90;cout << x << " " << y << endl;};lambda();cout << endl;//查看数值是否被修改cout << x << " " << y << endl;
}

[this]

[this]:表示值传递方式捕捉当前的this指针

class MyClass {
public:int value;MyClass(int v) : value(v) {}void printValuePlusTen() {// 使用 [this] 捕获当前对象的 this 指针  auto lambda = [this]() {std::cout << this->value + 10 << std::endl;};lambda(); // 输出 value 的值加 10  }
};int main() 
{MyClass obj(5);obj.printValuePlusTen(); // 输出: 15  cout << obj.value << endl; //输出5return 0;
}

在这里插入图片描述
需要注意的是,由于this指针是通过值传递的,因此lambda内部对this指针的拷贝进行操作时,不会影响到原始的this指针或对象本身。

除了这样,还可以混合使用:

语法上捕捉列表可由多个捕捉项组成,并以逗号分割。
比如:[=, &a, &b]:以引用传递的方式捕捉变量a和b,值传递方式捕捉其他所有变量
[&,a, this]:值传递方式捕捉变量a和this,引用方式捕捉其他变量

lambda的赋值

注意一下,就算两个lambda函数的捕获列表,参数,函数体都是一样的,这两个lambda本质上类型不一样,无法互相赋值:

int main()
{int x = 10;int y = 19;cout << x << " " << y << endl;//使用lambda表达式auto s1 = [&x, &y](){int temp;temp = x;x = y;y = temp;};auto s2 = [&x, &y]() {int temp;temp = x;x = y;y = temp;};s1 = s2;}

会报错:
在这里插入图片描述在这里插入图片描述

function包装器

现在我们学习了lambda,现在我们调用一个函数有多种方法了:
函数指针,仿函数,lambda,这有时候方法多了,用法就会混,有没有什么方法可以将他们统一起来呢?

C++11中引入了function

function 是 C++ 标准库 头文件中定义的一个模板类,它包装了任何可调用的目标(函数、lambda 表达式、函数对象等),允许你以一种统一的方式来存储和调用它们。std::function 的一个关键特性是其类型擦除(type erasure)能力,这意味着你可以使用同一个 std::function 对象来存储不同类型的可调用对象,只要它们具有兼容的调用签名。

举个例子:

//函数指针
void Swap_fuc(int& r1, int& r2)
{int temp = r1;r1 = r2;r2 = temp;
}//仿函数
struct Swap
{void operator()(int& r1,int& r2){int temp = r1;r1 = r2;r2 = temp;}
};int main()
{//lambda表达式auto s1 = [](int& r1, int& r2) {int temp = r1;r1 = r2;r2 = temp;};
}

function可以将这三个很好的结合起来:

#include<functional>
//函数指针
void Swap_fuc(int& r1, int& r2)
{int temp = r1;r1 = r2;r2 = temp;
}//仿函数
struct Swap
{void operator()(int& r1,int& r2){int temp = r1;r1 = r2;r2 = temp;}
};int main()
{//lambda表达式auto s1 = [](int& r1, int& r2) {int temp = r1;r1 = r2;r2 = temp;};function<void(int&, int&)> funtion1;//接收函数指针int r1 = 10;int r2 = 90;cout << "Swap_fuc交换之前的值:" << endl;cout << r1 << " " << r2 << endl;funtion1 = Swap_fuc;funtion1(r1,r2);cout << "交换之后的值:" << endl;cout << r1 << " " << r2 << endl;cout << endl;//仿函数cout << "Swap()交换之前的值:" << endl;cout << r1 << " " << r2 << endl;funtion1 = Swap();funtion1(r1, r2);cout << "交换之后的值:" << endl;cout << r1 << " " << r2 << endl;cout << endl;//lambdacout << "lambda交换之前的值:" << endl;cout << r1 << " " << r2 << endl;funtion1 = s1;funtion1(r1, r2);cout << "交换之后的值:" << endl;cout << r1 << " " << r2 << endl;cout << endl;}

在这里插入图片描述

function成员函数的包装

这里注意一下function对成员函数的包装要加上**&**:

class MyClass
{
public:void func_1(int& r1){cout << "func_1:" << r1 << endl;}void func_2(int& r2){cout << "func_2:" << r2 << endl;}
};int main()
{function<void(int&)> s = &MyClass::func_1;
}

但是,会报错:
在这里插入图片描述在这里插入图片描述这个错误信息好像说,类型好像不一样,好像有一个this指针,我们得加上:
在这里插入图片描述这个时候,调用这个函数就会稍微复杂一点:
在这里插入图片描述
在这里插入图片描述
如果嫌弃这样还是过于麻烦,我们可以传对象:
在这里插入图片描述这样还是太过于复杂,有没有什么办法呢,有的,我们有bind

bind绑定参数

std::bind是C++标准库中的一个功能,它用于将可调用对象(如函数、函数对象或lambda表达式)与参数绑定在一起,生成一个新的可调用对象。对于成员函数,std::bind特别有用,因为它允许你指定一个对象实例来调用该成员函数。

举一个简单的例子:

void Swap(int& r1, int& r2)
{int temp = r1;r1 = r2;r2 = temp;
}int main()
{//function<void(MyClass,int&)> s = &MyClass::func_1;//int u = 90;//s(MyClass(), u); //传一个匿名对象auto NewSwap = bind(&Swap, 20, placeholders::_1);int x = 89;NewSwap(x);cout << x << endl;
}

这里我指定函数是Swap绑定了第一个参数为20,之后placeholders::_1(_2, _3)表示要传的第一个参数,之后会用新绑定的NewSwap这个对象来调用:
在这里插入图片描述
我们可以利用这一点来简化代码:

class MyClass
{
public:void func_1(int& r1){cout << "func_1:" << r1 << endl;}void func_2(int& r2){cout << "func_2:" << r2 << endl;}
};
int main()
{//function<void(MyClass,int&)> s = &MyClass::func_1;//int u = 90;//s(MyClass(), u); //传一个匿名对象//auto NewSwap = bind(&Swap, 20, placeholders::_1);//int x = 89;//NewSwap(x);//cout << x << endl;function<void(int&)> s = bind(&MyClass::func_1,MyClass(), placeholders::_1);int x = 89;s(x); 
}

在这里插入图片描述

相关文章:

C++——C++11(3)

C——C11&#xff08;3&#xff09; lambda表达式&#xff08;匿名的仿函数对象&#xff09;一些注意点lambda捕捉列表[][&][this] lambda的赋值 function包装器function成员函数的包装 bind绑定参数 我们今天接着来了解一下C11一些新的特性&#xff0c;如果还没有看过上两…...

更改el-tabs默认样式,实现tab标签居中显示,标签对应内容使用另一个div显示

首先看效果图 如图所示&#xff0c;标签在浏览器窗口居中&#xff0c;但是下面的内容依然是默认从左到右&#xff0c;不会受到tab样式的影响 <template><div><div style"display: flex; justify-content: center; align-items: center;"><el-…...

微信小程序原生<map>地图实现标记多个位置以及map 组件 callout 自定义气泡

一、老规矩先上效果图: 二、在pages文件夹下新建image文件夹用来存放标记的图片。 三、代码片段 也可以参考小程序文档:https://developers.weixin.qq.com/miniprogram/dev/component/map.html index.wxml代码 <mapid="map"style="width: 100%; height:1…...

外包干了3天,技术明显进步。。。。。

先说一下自己的情况&#xff0c;本科生&#xff0c;19年通过校招进入南京某软件公司&#xff0c;干了接近2年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了2年的功能测试&…...

Transformer学习笔记(二)

一、文本嵌入层Embedding 1、作用&#xff1a; 无论是源文本嵌入还是目标文本嵌入&#xff0c;都是为了将文本中词汇的数字表示转变为向量表示&#xff0c;希望在这样的高维空间捕捉词汇间的关系。 二、位置编码器Positional Encoding 1、作用&#xff1a; 因为在Transformer…...

C#求水仙花数

目录 1.何谓水仙花数 2.求三位数的水仙花数 3.在遍历中使用Math.DivRem方法再求水仙花数 1.何谓水仙花数 水仙花数&#xff08;Narcissistic number&#xff09;是指一个 n 位正整数&#xff0c;它的每个位上的数字的 n 次幂之和等于它本身。例如&#xff0c;153 是一个 3 …...

FFmpeg转码参数说明及视频转码示例

-b : 设置音频或者视频的转码码率 -b:v 只设置视频码率 -b:a 只设置音频码率 -ab: 只设置音频码率, 默认码率大小为: 128k bit/s -g: 设置视频GOP大小,表示I帧之间的间隔,默认为12 -ar: 设置音频采样率,默认0 -ac: 设置音频通道数量 默认0 -bf: 设置连…...

qiankun:vite/webpack项目配置

相关博文&#xff1a; https://juejin.cn/post/7216536069285429285?searchId202403091501088BACFF113F980BA3B5F3 https://www.bilibili.com/video/BV12T411q7dq/?spm_id_from333.337.search-card.all.click qiankun结构&#xff1a; 主应用base&#xff1a;vue3historyv…...

【Linux】深入了解Linux磁盘配额:限制用户磁盘空间的利器

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;Linux ⛳️ 功不唐捐&#xff0c;玉汝于成 前言 在多用户环境下管理磁盘空间是服务器管理中的一项重要任务。Linux提供了强大的磁盘配额功能&#xff0c;可以帮助管理员限制用户或组对文件系统…...

Kamailio Debian安装

新方法是&#xff1a; apt install -y gnupg2 wget -O- https://deb.kamailio.org/kamailiodebkey.gpg | gpg --dearmor | tee /usr/share/keyrings/kamailio.gpg 老方法是&#xff1a; apt install -y gnupg2 wget -O- http://deb.kamailio.org/kamailiodebkey.gpg | apt-key…...

web学习笔记(三十四)

目录 1.面向对象的特征 2.面向对象的继承方式 3.正则表达式 3.1如何创建正则表达式 3.2边界符 3.2[ ]方括号 3.3正则表达式中相关的方法汇总 1.面向对象的特征 封装性&#xff1a;就像是把东西放在一个密封的盒子里一样&#xff0c;只让外部使用者通过指定的接口来访…...

2024/03/16----面试中遇到的一些面试题

1.请简单的说一下IOC&#xff0c;AOP 1.1 IOC 控制反转&#xff08;IOC&#xff09;是一种设计思想&#xff0c;就是将原本在程序中需要手动创建对象&#xff0c;现在交由Spring管理创建&#xff0c;从而降低代码之间的耦合度。 IoC 最常见以及最合理的实现方式叫做依赖注入…...

【SysBench】Linux 安装 sysbench-1.20

安装目的是为了对 MySQL 8.0.x 、PostgreSQL 进行基准测试。 0、sysbench 简介 sysbench 是一个可编写脚本的多线程基准测试工具&#xff0c;基于 LuaJIT 。 它最常用于数据库基准测试&#xff0c;但也可以 用于创建任意不涉及数据库服务器的复杂工作负载。 sysbench 附带以…...

设计模式 — — 代理模式

一、是什么 代理模式&#xff08;Proxy Pattern&#xff09;是为一个对象提供一个代用品或占位符&#xff0c;以便控制对它的 生活场景&#xff1a; 租房、买房&#xff0c;比如链家等房屋中介机构&#xff0c;起到的作用就是代理 二、使用 const proxy new Proxy(target, …...

【高通camera hal bug分析】高通自带相机镜像问题

首先打了两个log&#xff0c;一个是开启镜像的log&#xff0c;还有一个是没有开启镜像的log&#xff0c;如果我们开启镜像以后&#xff0c;观察开启镜像log发现 , 这段代码走的没有任何问题&#xff0c;因为Flip的值等于1了。 关闭镜像log如下&#xff1a; 如果我们不开启镜像…...

EPICS和Arduino Uno之间基于串行文本协议的控制开发

Arduino Uno的串口服务程序设置如文本的串口通信协议设计以及在Arduino上的应用-CSDN博客中所示。通过在串口上发送约定的文本协议&#xff0c;它实现的功能如下&#xff1a; 实现功能&#xff1a; 读取三路0.0V~5.0V模拟量输入&#xff0c;读取端口A0~A2设置三路0.0V~5.0V的模…...

数据结构的概念大合集02(线性表)

概念大合集02 1、线性表及其逻辑结构1.1 线性表的定义1.2 线性表的基本操作 2、线性表的顺序存储结构2.1 顺序表 3、线性表的链式存储3.1 链表3.1.1 头结点&#xff08;头指针&#xff09;&#xff0c;首指针&#xff0c;尾指针&#xff0c;尾结点3.1.2 单链表3.1.3 双链表3.1.…...

CSS3DRenderer, CSS3DSprite API 使用案例demo

CSS3DRenderer, CSS3DSprite API 使用案例demo <!DOCTYPE html> <html><head><title>three.js css3d - sprites</title><meta charset"utf-8"><meta name"viewport" content"widthdevice-width, user-scalabl…...

河马优化算法(HO)-2024年Nature子刊新算法 公式原理详解与性能测评 Matlab代码免费获取

声明&#xff1a;文章是从本人公众号中复制而来&#xff0c;因此&#xff0c;想最新最快了解各类智能优化算法及其改进的朋友&#xff0c;可关注我的公众号&#xff1a;强盛机器学习&#xff0c;不定期会有很多免费代码分享~ 目录 原理简介 一、种群初始化 二、河马在河流或…...

SLAM 算法综述

LiDAR SLAM 其主要思想是通过两个算法&#xff1a;一个高频激光里程计进行低精度的运动估计&#xff0c;即使用激光雷达做里程计计算两次扫描之间的位姿变换&#xff1b;另一个是执行低频但是高精度的建图与校正里程计&#xff0c;利用多次扫描的结果构建地图&#xff0c;细化位…...

Vue记事本应用实现教程

文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展&#xff1a;显示创建时间8. 功能扩展&#xff1a;记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

什么是库存周转?如何用进销存系统提高库存周转率?

你可能听说过这样一句话&#xff1a; “利润不是赚出来的&#xff0c;是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业&#xff0c;很多企业看着销售不错&#xff0c;账上却没钱、利润也不见了&#xff0c;一翻库存才发现&#xff1a; 一堆卖不动的旧货…...

Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!

一、引言 在数据驱动的背景下&#xff0c;知识图谱凭借其高效的信息组织能力&#xff0c;正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合&#xff0c;探讨知识图谱开发的实现细节&#xff0c;帮助读者掌握该技术栈在实际项目中的落地方法。 …...

大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计

随着大语言模型&#xff08;LLM&#xff09;参数规模的增长&#xff0c;推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长&#xff0c;而KV缓存的内存消耗可能高达数十GB&#xff08;例如Llama2-7B处理100K token时需50GB内存&a…...

面向无人机海岸带生态系统监测的语义分割基准数据集

描述&#xff1a;海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而&#xff0c;目前该领域仍面临一个挑战&#xff0c;即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...

热烈祝贺埃文科技正式加入可信数据空间发展联盟

2025年4月29日&#xff0c;在福州举办的第八届数字中国建设峰会“可信数据空间分论坛”上&#xff0c;可信数据空间发展联盟正式宣告成立。国家数据局党组书记、局长刘烈宏出席并致辞&#xff0c;强调该联盟是推进全国一体化数据市场建设的关键抓手。 郑州埃文科技有限公司&am…...

Visual Studio Code 扩展

Visual Studio Code 扩展 change-case 大小写转换EmmyLua for VSCode 调试插件Bookmarks 书签 change-case 大小写转换 https://marketplace.visualstudio.com/items?itemNamewmaurer.change-case 选中单词后&#xff0c;命令 changeCase.commands 可预览转换效果 EmmyLua…...

【Linux】Linux安装并配置RabbitMQ

目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的&#xff0c;需要先安…...

Unity-ECS详解

今天我们来了解Unity最先进的技术——ECS架构&#xff08;EntityComponentSystem&#xff09;。 Unity官方下有源码&#xff0c;我们下载源码后来学习。 ECS 与OOP&#xff08;Object-Oriented Programming&#xff09;对应&#xff0c;ECS是一种完全不同的编程范式与数据架构…...

TMC2226超静音步进电机驱动控制模块

目前已经使用TMC2226量产超过20K,发现在静音方面做的还是很不错。 一、TMC2226管脚定义说明 二、原理图及下载地址 一、TMC2226管脚定义说明 引脚编号类型功能OB11电机线圈 B 输出 1BRB2线圈 B 的检测电阻连接端。将检测电阻靠近该引脚连接到地。使用内部检测电阻时,将此引…...