当前位置: 首页 > 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;细化位…...

搭建Hadoop3.x完全分布式集群

零、资源准备 虚拟机相关&#xff1a; VMware workstation 16&#xff1a;虚拟机 > vmware_177981.zipCentOS Stream 9&#xff1a;虚拟机 > CentOS-Stream-9-latest-x86_64-dvd1.iso Hadoop相关 jdk1.8&#xff1a;JDK > jdk-8u261-linux-x64.tar.gzHadoop 3.3.6&am…...

linux常用命令(二)

目录 前言 常用命令 1.ls命令 2. cd命令 3.pwd命令 4.mkdir 命令 5. rmdir 命令 6.rm 命令 7.cp命令 8.mv命令 9.touch命令 10.cat命令 11.more命令 12.less命令 13.head命令 14.tail命令 15.tail命令 16.find命令 17.tar命令 18.gzip命令 19.gunzip命令 …...

【Vue】Request模块 - axios 封装Vuex的持久化存储

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;Vue ⛺️稳中求进&#xff0c;晒太阳 Request模块 - axios 封装 使用axios来请求后端接口&#xff0c;一般会对axios进行一些配置&#xff08;比如配置基础地址&#xff0c;请求响应拦截器…...

【2024第一期CANN训练营】4、AscendCL推理应用开发

文章目录 【2024第一期CANN训练营】4、AscendCL推理应用开发1. 创建代码目录2. 构建模型2.1 下载原始模型文件2.2 使用ATC工具转换模型2.3 注意事项 3. 模型加载3.1 示例代码 4. 模型执行4.1 获取模型描述信息4.2 准备输入/输出数据结构4.3 执行模型推理4.4 释放内存和数据类型…...

Rust 构建开源 Pingora 框架可以与nginx媲美

一、概述 Cloudflare 为何弃用 Nginx&#xff0c;选择使用 Rust 重新构建新的代理 Pingora 框架。Cloudflare 成立于2010年&#xff0c;是一家领先的云服务提供商&#xff0c;专注于内容分发网络&#xff08;CDN&#xff09;和分布式域名解析。它提供一系列安全和性能优化服务…...

MediaCodec源码分析 ACodec状态详解

前言 本文分析ACodec状态机,ACodec是MediaCodec的底层实现,在MediaCodec命令下切换不同状态进行编解码,基于7.0代码。 ACodec状态介绍 UninitializedState:未初始化状态。 在业务层调用MediaCodec. createByCodecName 完成后切换到LoadedState。 LoadedState:表示解码器…...

【Elasticsearch】windows安装elasticsearch教程及遇到的坑

一、安装参考 1、安装参考&#xff1a;ES的安装使用(windows版) elasticsearch的下载地址&#xff1a;https://www.elastic.co/cn/downloads/elasticsearch ik分词器的下载地址&#xff1a;https://github.com/medcl/elasticsearch-analysis-ik/releases kibana可视化工具下载…...

如何快速搭建物联网工业云平台

随着物联网技术的快速发展&#xff0c;物联网工业云平台已经成为推动工业领域数字化转型的重要引擎。合沃作为专业的物联网云服务提供商&#xff0c;致力于为企业提供高效、可靠的物联网工业云平台解决方案。本文将深入探讨物联网工业云平台的功能、解决行业痛点的能力以及如何…...

Spring Data访问Elasticsearch----Elasticsearch对象映射

Spring Data访问Elasticsearch----Elasticsearch对象映射 一、元模型(Meta Model)对象映射1.1 映射注解概述1.1.1 控制向Elasticsearch写入和从其读取哪些属性1.1.2 日期格式映射1.1.3 Range类型1.1.4 映射的字段名1.1.5 Non-field-backed属性1.1.6 其他属性注解 1.2 映射规则1…...

Linux之shell循环

华子目录 for循环带列表的for循环格式分析示例shell允许用户指定for语句的步长&#xff0c;格式如下示例 不带列表的for循环示例 基于C语言风格的for循环格式示例注意 while循环格式示例 until循环作用格式示例 循环控制breakcontinue详细语法示例 循环嵌套示例 for循环 for循…...