C++11新增重要标准(下)

news2025/6/8 18:53:30

前言

一,forward(完美转发)

二,可变参数模板

三,emplace系列接口

四,新增类功能

五,default与delete

六,lambda表达式

七,包装器

八,bind


在C++11中新增的容器:unordered_set,unordered_map

接口:emplace_back与各个容器的push_back右值引用版本提高了程序运行的效率,其他一些新增标准无非是锦上添花。

一,forward(完美转发)

template<class T>
void funa(T& x)
{
	cout << "左值成功" << endl;
}
template<class T>
void funa(T&& x)
{
	cout << "右值成功" << endl;
}
template<class T>
void func(T&& x)
{
	funa(x);
}
int main()
{
	int&& a= 3;//a是右值引用表达式
	func(a);//这里传入的a的属性为左值
	//func(3);//3是右值
	return 0;
}

1)右值被右值引用绑定之后,右值引用表达式的属性会变为左值,所以将x往下传时x的属性是左值所以对应传入的函数就是funa(int& x)

func(3);//3是右值

直接传入右值时,传入时3的属性是右值,传入函数时推导3的类型为int,与函数参数类型折叠成int&& x,这个时候x为右值引用表达式,属性会改为左值。

解决方法:在func函数中如果需要把函数参数继续往另外一个函数传递的话就需要在需要传参的地方给参数加上forward<T>(),T是参数传入时的类型,这里一定要注意只能传入T(类型)如果传入其他的编译器会推导不出来该参数原来的属性。

二,可变参数模板

可变参数模板支持可变参数的函数模板和类模板,参数的数量可以是0,也可以为其他个数个。

//可变参数的类模板
template<class ...Args>
class student
{};
//可变参数的函数模板
template<class ...Args>
void func(Args... args)
{}

这里需要注意的是上述...的位置

可变参数模板也支持折叠引用规则,所以在使用时会非常的方便。

template <class ...Args>
void Print(Args&&... args)
{
	cout << sizeof...(args) << endl;
}
int main()
{
	double x = 2.2;
	Print();
	Print(1);
	Print(1, string("xxxxx"));

	Print(1.1, string("xxxxx"), x);   // 
	return 0;
}

上面代码Print函数中传入不同个数类型的参数,因为Print是可变参数模板函数,他会根据传入的参数自动生成对应的函数。

可以通过sizeof...()来计算包中的参数有多少个。

包扩展:对于⼀个参数包,我们除了能计算他的参数个数,我们能做的唯⼀的事情就是扩展它,当扩展⼀个 包时,我们还要提供用于每个扩展元素的模式,扩展⼀个包就是将它分解为构成的元素,对每个元素应用模式,获得扩展后的列表。我们通过在模式的右边放⼀个省略号(...)来触发扩展操作。

三,emplace系列接口

 template <class... Args> void emplace_back (Args&&... args);
 template <class... Args> iterator emplace (const_iterator position, 
Args&&... args);

可以看到这系列接口都是使用可变参数模板来实现的,在功能上还兼容push与insert系列,emplace系列接口在插入对象时可以直接插入该对象的参数,直接根据参数构造对象,这样会更高效些。

使用传入参数构造对象时,他会不断的将参数包往下传递,直到为空时会推导出该对象的类型,直接匹配该容器的构造。

结论:emplace_back总体而言是更高效,推荐以后使用emplace系列替代insert和push系列。

顺便说一句,在进行参数传递时如果是Args&&... args的参数包,需要继续往下传递参数时就需要使用完美转发。

四,新增类功能

移动构造:        

        如果你没有自己实现移动构造函数,且没有实现析构函数、拷贝构造、拷贝赋值重载中的任意⼀个。那么编译器会自动生成⼀个默认移动构造。默认生成的移动构造函数,对于内置类型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现移动构造,如果实现了就调用移动构造,没有实现就调⽤拷⻉构造。

移动赋值重载:

如果你没有自己实现移动赋值重载函数,且没有实现析构函数、拷贝构造、拷贝赋值重载中的任意 ⼀个,那么编译器会自动生成⼀个默认移动赋值。默认生成的移动构造函数,对于内置类型成员会 执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现移动赋值,如果实现了就调 用移动赋值,没有实现就调⽤拷贝赋值。

如果自己实现了这两个,编译器就不会自动生成。

五,default与delete

default:如果你需要使用默认函数,但是该函数没有生成,可以使用该关键字强制生成该函数,例如我们自己实现了拷贝构造函数时,编译器就不会自己生成默认移动构造函数,这个时候就可以使用该关键字强制默认移动构造生成。

class Data
{
	Data(const Data& d)
		:y(d.y)
		,m(d.m)
		,d(d.d)
	{ }
	Data(Data&& dd) = default;

private:
	int y;
	int m;
	int d;
};

delete:如果你不想让某些默认函数生成的话就可以使用该关键字阻止该函数生成,使用方法与default相同。

六,lambda表达式

lambda表达式本质是⼀个匿名函数对象,跟普通函数不同的是他可以定义在函数内部。

使用auto或者用模板参数定义的对象去接收lambda对象。

格式:[捕获列表](参数列表)->返回值类型{函数体}

auto add = [](int a, int b)->int {return a + b; };

上面就是简单的lambda表达式的定义

捕获列表:lambda表达式中默认只能使用参数列表中的变量进行运算,如果需要使用外层作用域变量就需要需要进行捕捉

捕获分为传值捕获和传引用捕获,传值捕获不能修改变量的值,传引用可以改变变量的值

void func()
{
	int a = 3, b = 2, c = 8;
	auto hh = [a, &b] {//捕获列表中可以加入在上文定义出现的参数
		a++;//传值捕获不能修改
		b++;//传引用可以修改值,在里面修改之后原变量的值也会跟着修改,因为是传引用
		return a + b;
		};
	int d = 7;//d不能被捕获,因为他在表达式下面定义的
}
int x = 0;
// 捕捉列表必须为空,因为全局变量不⽤捕捉就可以⽤,没有可被捕捉的变量
auto func1 = []()
	{
		x++;
	};

int main()
{
	//只能⽤当前lambda局部域和捕捉的对象和全局对象
	int a = 0, b = 1, c = 2, d = 3;
	auto func1 = [a, &b]
		{
			b++;
			int ret = a + b;
			return ret;
		};
	cout << func1() << endl;


	auto func2 = [=]//捕捉所有的变量(传值)
		{
			int ret = a + b + c;
			return ret;
		};
	cout << func2() << endl;

	auto func3 = [&]//表示捕捉的变量都是传引用捕捉
		{
			a++;
			c++;
			d++;
		};
	func3();
	cout << a << " " << b << " " << c << " " << d << endl;

	auto func4 = [&, a, b]//表示除a,b是使用传值捕捉,其他都是使用传引用捕捉
		{
			//a++;
			//b++;
			c++;
			d++;
			return a + b + c + d;
		};
	func4();
	cout << a << " " << b << " " << c << " " << d << endl;


	auto func5 = [=, &a, &b]//表示除a,b是使用传引用捕捉,其他都是使用传值捕捉
		{
			a++;
			b++;
			return a + b + c + d;
		};
	func5();
	cout << a << " " << b << " " << c << " " << d << endl;


	static int m = 0;
	auto func6 = []//静态成员变量与全局变量不需要捕捉就能使用
		{
			int ret = x + m;
			return ret;
		};

	auto func7 = [=]()mutable//默认捕捉的变量都是被const修饰的,添加该关键字取消常性
		{					//需要注意的是虽然取消了常性能在表达式中被修改,但是原来的值不会被修改
			a++;
			b++;
			c++;
			d++;
			return a + b + c + d;
		};
	cout << func7() << endl;
	cout << a << " " << b << " " << c << " " << d << endl;
	return 0;
}

七,包装器

template <class T>
 class function;     
// undefined
 template <class Ret, class... Args>
 class function<Ret(Args...)>;

包装器,顾名思义可以将某些东西进行包装统一,他主要作用是可以将一切可调用对象进行包装例如:函数指针,仿函数,lambda,bind表达式等等。

int f(int a, int b)//函数
{
	return a + b;
}

struct Functor//仿函数
{
public:
	int operator() (int a, int b)
	{
		return a + b;
	}
};

class Plus//成员函数
{
public:
	Plus(int n = 10)
		:_n(n)
	{
	}
	static int plusi(int a, int b)
	{
		return a + b;
	}
	double plusd(double a, double b)
	{
		return (a + b) * _n;
	}
private:
	int _n;
};


int main()
{
	// 包装各种可调⽤对象
	function<int(int, int)> f1 = f;
	function<int(int, int)> f2 = Functor();
	function<int(int, int)> f3 = [](int a, int b) {return a + b; };
	cout << f1(1, 1) << endl;
	cout << f2(1, 1) << endl;
	cout << f3(1, 1) << endl;
	// 包装静态成员函数

	// 成员函数要指定类域并且前⾯加&才能获取地址
	function<int(int, int)> f4 = &Plus::plusi;
	cout << f4(1, 1) << endl;
	// 包装普通成员函数
	// 普通成员函数还有⼀个隐含的this指针参数,所以绑定时传对象或者对象的指针过去都可以
	function<double(Plus*, double, double)> f5 = &Plus::plusd;
	Plus pd;
	cout << f5(&pd, 1.1, 1.1) << endl;
	function<double(Plus, double, double)> f6 = &Plus::plusd;
	cout << f6(pd, 1.1, 1.1) << endl;
	cout << f6(pd, 1.1, 1.1) << endl;
	function<double(Plus&&, double, double)> f7 = &Plus::plusd;
	cout << f7(move(pd), 1.1, 1.1) << endl;
	cout << f7(Plus(), 1.1, 1.1) << endl;
	return 0;
}

八,bind

        bind也是个函数模板,调用bind的⼀般形式: auto newCallable = bind(callable,arg_list); 其中 newCallable本身是⼀个可调用对象,arg_list是⼀个逗号分隔的参数列表,对应给定的callable的 参数。

作用:

1)修改参数的位置

using placeholders::_1;
using placeholders::_2;
using placeholders::_3;

int sub(int a, int b)
{
	return (a - b);
}

int main()
{
	auto sub1 = bind(sub, _1, _2);
	cout << sub1(5,10) << endl;
	auto sub2 = bind(sub, _2, _1);
	cout << sub2(5, 10) << endl;
	return 0;
}

2)可以固定某个参数的值保持不变,变为固定值

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2404443.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【第六篇】 SpringBoot的日志基础操作

简介 日志系统在软件开发中至关重要&#xff0c;用于调试代码、记录运行信息及错误堆栈。本篇文章不仅详细介绍了日志对象的创建及快速使用&#xff0c;还说明了日志持久化的两种配置方式和滚动日志的设置。实际开发需根据场景选择合适的日志级别和存储策略。文章内容若存在错误…

Pluto论文阅读笔记

主要还是参考了这一篇论文笔记&#xff1a;https://zhuanlan.zhihu.com/p/18319150220 Pluto主要有三个创新点&#xff1a; 横向纵向用lane的query来做将轨迹投回栅格化地图&#xff0c;计算碰撞loss对数据进行正增强和负增强&#xff0c;让正增强的结果也无增强的结果相近&a…

matlab 2024a ​工具箱Aerospsce Toolbox报错​

Matlab R2024a中Aerospsce Toolbox报错 警告&#xff1a;Aerospace Toolbox and Aerospace Blockset licenses are required in ‘built-in/Spacecraft Dynamics’ 找到安装路径\MATLAB\R2024a\licenses文件夹license_****_R2024a.lic 里面工具箱名称出错&#xff0c;手动修改…

使用有限计算实现视频生成模型的高效训练

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 抽象 视频生成的最新进展需要越来越高效的训练配方&#xff0c;以减轻不断上升的计算成本。在本报告中&#xff0c;我们介绍了 ContentV&#xff0c;这是一种 8B 参数文本到视频模型&#xff0c;在 256 …

Server2003 B-1 Windows操作系统渗透

任务环境说明&#xff1a; 服务器场景&#xff1a;Server2003&#xff08;开放链接&#xff09; 服务器场景操作系统&#xff1a;Windows7 1.通过本地PC中渗透测试平台Kali对服务器场景Windows进行系统服务及版本扫描渗透测试&#xff0c;并将该操作显示结果中Telnet服务对应的…

一次Oracle的非正常关闭

数据库自己会关闭吗&#xff1f; 从现象来说Oracle MySQL Redis等都会出现进程意外停止的情况。而这些停止都是非人为正常关闭或者暴力关闭&#xff08;abort或者kill 进程&#xff09; 一次测试环境的非关闭 一般遇到这种情况先看一下错误日志吧。 2025-06-01T06:26:06.35…

YOLO11解决方案之分析

概述 Ultralytics提供了一系列的解决方案&#xff0c;利用YOLO11解决现实世界的问题&#xff0c;包括物体计数、模糊处理、热力图、安防系统、速度估计、物体追踪等多个方面的应用。 Ultralytics提供了三种基本的数据可视化类型&#xff1a;折线图&#xff08;面积图&#xf…

yolov11与双目测距结合,实现目标的识别和定位测距(onnx版本)

一、yolov11双目测距基本流程 yolov11 双目测距的大致流程就是&#xff1a; 双目标定 --> 立体校正&#xff08;含消除畸变&#xff09; --> 立体匹配 --> 视差计算 --> 深度计算(3D坐标)计算 --> 目标检测 --> 目标距离计算及可视化 下面将分别阐述每…

基于51单片机和8X8点阵屏、独立按键的填充消除类小游戏

目录 系列文章目录前言一、效果展示二、原理分析三、各模块代码1、8X8点阵屏2、独立按键3、定时器04、定时器1 四、主函数总结 系列文章目录 前言 使用的是普中A2开发板。 【单片机】STC89C52RC 【频率】12T11.0592MHz 【外设】8X8点阵屏、独立按键 效果查看/操作演示&#x…

物联网技术发展与应用研究分析

文章目录 引言一、物联网的基本架构&#xff08;一&#xff09;感知层&#xff08;二&#xff09;网络层&#xff08;三&#xff09;平台层&#xff08;四&#xff09;应用层 二、物联网的关键技术&#xff08;一&#xff09;传感器技术&#xff08;二&#xff09;通信技术&…

金融系统渗透测试

金融系统渗透测试是保障金融机构网络安全的核心环节&#xff0c;它的核心目标是通过模拟攻击手段主动发现系统漏洞&#xff0c;防范数据泄露、资金盗取等重大风险。 一、金融系统渗透测试的核心框架 合规性驱动 需严格遵循《网络安全法》《数据安全法》及金融行业监管要求&am…

9.进程间通信

1.简介 为啥要有进程间通信&#xff1f; 如果未来进程之间要协同呢&#xff1f;一个进程要把自己的数据交给另一个进程&#xff01;进程是具有独立性的&#xff0c;所以把一个进程的数据交给另一个进程----基本不可能&#xff01;必须通信起来&#xff0c;就必须要有另一个人…

React 基础入门笔记

一、JSX语法规则 1. 定义虚拟DOM时&#xff0c;不要写引号 2.标签中混入JS表达式时要用 {} &#xff08;1&#xff09;.JS表达式与JS语句&#xff08;代码&#xff09;的区别 &#xff08;2&#xff09;.使用案例 3.样式的类名指定不要用class&#xff0c;要用className 4.内…

压测软件-Jmeter

1 下载和安装 1.1 检查运行环境 Jmeter需要运行在java环境&#xff08;JRE 或 JDK&#xff09;中 在window的"命令提示窗"查看安装的java版本: java -version 1.2 下载Jmeter 从Apache官网下载Jmeter安装包 1.3 解压和运行 解压后,进入bin文件夹,双击jmeter.bat即可…

NLP学习路线图(三十):微调策略

在自然语言处理领域,预训练语言模型(如BERT、GPT、T5)已成为基础设施。但如何让这些“通才”模型蜕变为特定任务的“专家”?微调策略正是关键所在。本文将深入剖析七种核心微调技术及其演进逻辑。 一、基础概念:为什么需要微调? 预训练模型在海量语料上学习了通用语言表…

leetcode刷题日记——1.组合总和

解答&#xff1a; class Solution { public:void dfs(vector<int>& candidates, int target, vector<vector<int>>& ans, vector<int>& combine, int idx) {if(idxcandidates.size()){//遍历完的边界return;}if(target0){//找完了能组成和…

关于单片机的基础知识(一)

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///计算机爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于单片机基础知识的相关内容&#xf…

Xilinx FPGA 重构Multiboot ICAPE2和ICAPE3使用

一、FPGA Multiboot 本文主要介绍基于IPROG命令的FPGA多版本重构&#xff0c;用ICAP原语实现在线多版本切换。需要了解MultiBoot Fallback点击链接。 如下图所示&#xff0c;ICAP原语可实现flash中n1各版本的动态切换&#xff0c;在工作过程中&#xff0c;可以通过IPROG命令切…

Redis专题-基础篇

题记 本文涵盖了Redis的各种数据结构和命令&#xff0c;Redis的各种常见Java客户端的应用和最佳实践 jedis案例github地址&#xff1a;https://github.com/whltaoin/fedis_java_demo SpringbootDataRedis案例github地址&#xff1a;https://github.com/whltaoin/springbootData…

springMVC-11 中文乱码处理

前言 本文介绍了springMVC中文乱码的解决方案&#xff0c;同时也贴出了本人遇到过的其他乱码情况&#xff0c;可以根据自身情况选择合适的解决方案。 其他-jdbc、前端、后端、jsp乱码的解决 Tomcat导致的乱码解决 自定义中文乱码过滤器 老方法&#xff0c;通过javaW…