【C++】第二十七节—C++11(下) | 可变参数模版+新的类功能+STL中一些变化+包装器

【C++】第二十七节—C++11(下) | 可变参数模版+新的类功能+STL中一些变化+包装器

Hi,好久不见,我是云边有个稻草人,偶尔中二的C++领域博主与你分享专业知识U·ェ·U

《C++》本篇文章所属专栏—持续更新中—欢迎订阅~

目录

五、可变参数模版

1. 基本语法及原理

2. 包扩展

方式一

方式二

3. empalce系列接口

六、新的类功能

1. 默认的移动构造和移动赋值

2. 成员变量声明时给缺省值

3. defult和delete

4. final与override

七、STL中一些变化

八、包装器

1. function

2. bind


正文开始——

五、可变参数模版

1. 基本语法及原理
  • C++11支持可变参数模板,也就是说支持可变数量参数的函数模板和类模板,可变数目的参数被称 为参数包,存在两种参数包:模板参数包,表示零或多个模板参数;函数参数包:表示零或多个函 数参数。
  • template void Func(Args... args) {}
  • template void Func(Args&... args) {}
  • template void Func(Args&&... args) {}
  • 我们用省略号来指出一个模板参数或函数参数的表示一个包,在模板参数列表中,class...或 typename...指出接下来的参数表示零或多个类型列表;在函数参数列表中,类型名后面跟...指出 接下来表示零或多个形参对象列表;函数参数包可以用左值引用或右值引用表示,跟前面普通模板 一样,每个参数实例化时遵循引用折叠规则。
  • 可变参数模板的原理跟模板类似,本质还是去实例化对应类型和个数的多个函数。
  • 这里我们可以使用sizeof...运算符去计算参数包中参数的个数。
template <class ...Args> void Print(Args&&... args) { cout << sizeof...(args) << endl; } int main() { double x = 2.2; Print(); // 包里有0个参数 Print(1); // 包里有1个参数 Print(1, string("xxxxx")); // 包里有2个参数 Print(1.1, string("xxxxx"), x); // 包里有3个参数 return 0; } // 原理1:编译本质这里会结合引用折叠规则实例化出以下四个函数 void Print(); void Print(int&& arg1); void Print(int&& arg1, string&& arg2); void Print(double&& arg1, string&& arg2, double& arg3); // 原理2:更本质去看没有可变参数模板,我们实现出这样的多个函数模板才能支持 // 这里的功能,有了可变参数模板,我们进一步被解放,他是类型泛化基础 // 上叠加数量变化,让我们泛型编程更灵活。 void Print(); template <class T1> void Print(T1&& arg1); template <class T1, class T2> void Print(T1&& arg1, T2&& arg2); template <class T1, class T2, class T3> void Print(T1&& arg1, T2&& arg2, T3&& arg3); // ...
2. 包扩展
  • 对于一个参数包,我们除了能计算他的参数个数,我们能做的唯一的事情就是扩展它,当扩展一个包时,我们还要提供用于每个扩展元素的模式,扩展一个包就是将它分解为构成的元素,对每个元素应用模式,获得扩展后的列表。我们通过在模式的右边放一个省略号(...)来触发扩展操作。底层的实现细节如图一所示。见方式一
  • C++还支持更复杂的包扩展,直接将参数包依次展开依次作为实参给一个函数去处理。见方式二

不支持用下面的方式去进行包扩展

// 可变模板参数 // 参数类型可变 // 参数个数可变 // 打印参数包内容 template <class ...Args> void Print(Args... args) { // 可变参数模板编译时解析 // 下面是运行获取和解析,所以不支持这样用 cout << sizeof...(args) << endl; for (size_t i = 0; i < sizeof...(args); i++) { cout << args[i] << " "; } cout << endl; }

见下面使用递归的一种包扩展的方式

方式一
void ShowList() { // 编译器时递归的终止条件,参数包是0个时,直接匹配这个函数 cout << endl; } template <class T, class ...Args> void ShowList(T x, Args... args) { cout << x << " "; // args是N个参数的参数包 // 调用ShowList,参数包的第一个传给x,剩下N-1传给第二个参数包 ShowList(args...); } // 编译时递归推导解析参数 template <class ...Args> void Print(Args... args) { ShowList(args...); } int main() { Print(1, string("xxxxx"), 2.2); return 0; } // 调用时 // 本质编译器将可变参数模板通过模式的包扩展, // 编译器推导的以下三个重载函数函数 //void ShowList(double x) //{ // cout << x << " ";ShowList(); //} //void ShowList(string x, double z) //{ // cout << x << " "; // ShowList(z); //} //void ShowList(int x, string y, double z) //{ // cout << x << " "; // ShowList(y, z); //} //void Print(int x, string y, double z) //{ // ShowList(x, y, z); //}

对上面包扩展的过程进行解析

图一
方式二
template <class T> const T & GetArg(const T & x) { cout << x << " "; return x; } template <class ...Args> void Arguments(Args... args) { } template <class ...Args> void Print(Args... args) { // 注意GetArg必须返回或者到的对象,这样才能组成参数包给Arguments Arguments(GetArg(args)...); } // 本质可以理解为编译器编译时,包的扩展模式 // 将上面的函数模板扩展实例化为下面的函数 // 是不是很抽象,C++11以后,只能说委员会的大佬设计语法思维跳跃得太厉害 //void Print(int x, string y, double z) //{ //Arguments(GetArg(x), GetArg(y), GetArg(z)); //} int main() { Print(1, string("xxxxx"), 2.2); return 0; }

稍稍解释一下:

3. empalce系列接口
  • template void emplace_back (Args&&... args);
  • template iterator emplace (const_iterator position, Args&&... args);
  •  C++11以后STL容器新增了empalce系列的接口,empalce系列的接口均为模板可变参数,功能上兼容push和 insert 系列,但是empalce还支持新玩法,假设容器为container,empalce还支持直接插入构造T对象的参数,这样有些场景会更高效一些,可

Read more

Linux:初始网络(上)

之前我们学习了linux的系统部分,从现在开始,我们将进入linux网络部分的学习,在正式开始学习网络之前,我们需要先了解一下什么网络,他是源自什么的,怎么发展的,以及协议的浅层意思,话不多说,现在开始 ⽹络基础概念 ⽹络发展 独⽴模式: 计算机之间相互独⽴ 在以前,计算机都是独立的,所以为了合作,只能A完成A的部分,然后将类似磁盘的存储数据的东西交给B,B再完成B的部分,然后教给C,C完成自己的部分,可想而知,这样效率缓慢 ⽹络互联: 多台计算机连接在⼀起, 完成数据共享 为了解决这种事情,有人提议将ABC三台电脑连接到一个服务器上,这样A完成之后只需要把数据给服务器,B只需要拉下服务器的数据就可以,不需要人跑来跑去送数据,这就是网络互联 局域⽹LAN: 计算机数量更多了, 通过交换机和路由器连接在⼀起 越来越多计算机这样,于是为了更好的联系,出现了交换机连接 ⼴域⽹WAN: 将远隔千⾥的计算机都连在⼀起 当局域网多了,于是他们又互相链接,

By Ne0inhk

安装WSL及Ubuntu遇到问题安全频道支持出错

问题描述 安装wsl及ubuntu的时候总数提示安全频道支持出错 原因 这个 “安全频道支持出错”,在 安装 WSL / Ubuntu 时非常常见,本质上不是 WSL 本身坏了,而是 Windows 的安全通信(TLS/SSL / 证书)出了问题。 一、这个错到底是什么意思? 安全频道(Security Channel / Schannel) 是 Windows 用来做 HTTPS / TLS 加密通信 的组件。 安装 WSL / Ubuntu 的过程里,需要: 访问 Microsoft Store 或从 微软服务器下载发行版 或通过 HTTPS 拉取包 一旦 Windows 的: TLS

By Ne0inhk
HarmonyOS应用开发实战(基础篇)Day09-《构建布局详解下》

HarmonyOS应用开发实战(基础篇)Day09-《构建布局详解下》

相对布局 (RelativeContainer) RelativeContainer 是 ArkUI 中一种基于相对定位规则的布局容器,允许子组件通过与其他组件或容器边缘的相对关系来确定自身位置。每个子组件需通过 id 标识,并通过 alignRules 属性声明其相对于其他元素的对齐规则(如“位于 A 的右侧”、“底部对齐 B”等)。 尽管功能强大,但 RelativeContainer 在实际项目中使用频率较低,主要原因包括: * 学习成本高:需理解复杂的对齐规则链; * 维护难度大:组件间耦合紧密,修改一处可能影响多处布局; * 响应式支持弱:难以适配多尺寸屏幕; * 性能开销:布局计算复杂度高于线性或弹性布局。 因此,除非有特殊需求(如自定义复杂仪表盘、拖拽编辑器、游戏 UI 等),一般推荐优先使用 Column、Row、Flex 或 Stack。 📚 深入学习: 若您对高级布局感兴趣,可查阅官方文档:

By Ne0inhk
【高级终端Termux】在安卓手机/平板上使用Termux 搭建 Debian 环境并运行 PC 级 Linux 应用教程(含安装WPS,VS Code)

【高级终端Termux】在安卓手机/平板上使用Termux 搭建 Debian 环境并运行 PC 级 Linux 应用教程(含安装WPS,VS Code)

Termux 搭建 Debian 环境并运行 PC 级 Linux 应用教程 一、前言 1. 背景 众所周知,最新搭载澎湃OS和鸿蒙OS的平板都内置了PC级WPS,办公效率直接拉满(板子终于从“泡面盖”升级为“生产力”了)。但问题来了:如果不是这两个系统,难道我们只能继续用平板盖泡面吗?当然不是!折腾了很长时间后,总算找到了一个好玩的东西:高级终端Termux 。现在,不仅能随时随地用WPS改文档,还能VSCode优雅地敲代码,再也不用背着电脑乱跑了。 由于每次搭建环境时都要去不同的平台找不同功能,有时还找不到,所以我决定自己写一篇博客,方便自己以后再搭建时直接“Ctrl C + Ctrl V”,顺便分享给有同样需求的小伙伴们。话不多说,直接开整! 2. 准备工作 * 一部安卓手机:性能越好,折腾起来越顺畅。 * Termux 应用: 不想去F-droid下载的看过来

By Ne0inhk