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

Python:操作 Excel 折叠

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...

通过Wrangler CLI在worker中创建数据库和表

官方使用文档&#xff1a;Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后&#xff0c;会在本地和远程创建数据库&#xff1a; npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库&#xff1a; 现在&#xff0c;您的Cloudfla…...

现代密码学 | 椭圆曲线密码学—附py代码

Elliptic Curve Cryptography 椭圆曲线密码学&#xff08;ECC&#xff09;是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础&#xff0c;例如椭圆曲线数字签…...

C++.OpenGL (10/64)基础光照(Basic Lighting)

基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...

Mysql中select查询语句的执行过程

目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析&#xff08;Parser&#xff09; 2.4、执行sql 1. 预处理&#xff08;Preprocessor&#xff09; 2. 查询优化器&#xff08;Optimizer&#xff09; 3. 执行器…...

【Go语言基础【12】】指针:声明、取地址、解引用

文章目录 零、概述&#xff1a;指针 vs. 引用&#xff08;类比其他语言&#xff09;一、指针基础概念二、指针声明与初始化三、指针操作符1. &&#xff1a;取地址&#xff08;拿到内存地址&#xff09;2. *&#xff1a;解引用&#xff08;拿到值&#xff09; 四、空指针&am…...

七、数据库的完整性

七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...

MySQL 8.0 事务全面讲解

以下是一个结合两次回答的 MySQL 8.0 事务全面讲解&#xff0c;涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容&#xff0c;并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念&#xff08;ACID&#xff09; 事务是…...

通过 Ansible 在 Windows 2022 上安装 IIS Web 服务器

拓扑结构 这是一个用于通过 Ansible 部署 IIS Web 服务器的实验室拓扑。 前提条件&#xff1a; 在被管理的节点上安装WinRm 准备一张自签名的证书 开放防火墙入站tcp 5985 5986端口 准备自签名证书 PS C:\Users\azureuser> $cert New-SelfSignedCertificate -DnsName &…...

2.2.2 ASPICE的需求分析

ASPICE的需求分析是汽车软件开发过程中至关重要的一环&#xff0c;它涉及到对需求进行详细分析、验证和确认&#xff0c;以确保软件产品能够满足客户和用户的需求。在ASPICE中&#xff0c;需求分析的关键步骤包括&#xff1a; 需求细化&#xff1a;将从需求收集阶段获得的高层需…...