从0开始的数据结构速过——番外(1)

embedded/2024/11/24 4:26:53/

目录

尝试

思考与架构设置

编写!

一些额外知识的补充

可变参数模板

std::common_type

std::forward


这是《数据结构从0开始》的一个番外。实际上是介绍一下一些现代C++的写法。这里以快速构建std::array作为契机来说明一下一些现代C++的语法。

尝试

我们在这里呢,需要完成一个比较底层的工作:那就是为任何type的array构造一个方便的函数。他接受任意长度的参数,然后返回这些参数组成的array,就是这样的简单!

想一想,你需要做什么工作呢?

思考与架构设置

显然,我们需要为任何type构建,意味着我们需要使用现代C++的模板来完成这个工作。接受任意长度的参数说明我们需要可变参数模板。std::array还需要一个常量说明长度,意味着我们需要一个编译时推导的长度。

那这样看,至少我们现在需要的是:

  • 可变的参数模板

  • 使用sizeof... (args)来描述我们的参数长度!

编写!

第一步,我们按照函数参数模板的起手来干活,我们需要的是:

#include <array>
#include <type_traits>
​
template<typename ... Args>
auto construct_array(Args&&... args) -> std::array<ATypename, Args_number>{return ...
} 

好吧,还有好多东西并不确定!我们知道,有的时候我们构造数组,需要抽取公共类型。也就是需要使用std::common_type来做这个事情。以及,需要typename强制告知我后面的标识符是一个类型名称而不是一个什么别的东西。因此,ATypename就可以被替代为:

std::common_type<Args...>::type

至于参数的长度,那也就是使用sizeof...(args)表述

#include <array>
#include <type_traits>
​
template<typename ... Args>
auto construct_array(Args&&... args) -> std::array<typename std::common_type<Args...>::type, sizeof...(args)>{using commonType = std::common_type<Args...>::type; // 太长了,rename一下return { std::forward<commonType>(args)... };
}
​

下一步就是具体干活,实现函数体

#include <array>
#include <type_traits>
​
template<typename ... Args>
auto construct_array(Args&&... args) -> std::array<typename std::common_type<Args...>::type, sizeof...(args)>{using commonType = std::common_type<Args...>::type; // 太长了,rename一下return { std::forward<commonType>(args)... };
}

下面我们来试试看:非常的好!

一些额外知识的补充

可变参数模板

C++11增强了模板功能,允许模板定义中包含0到任意个模板参数,这就是可变参数模板。可变参数模板的加入使得C++11的功能变得更加强大,而由此也带来了许多神奇的用法。

在语义上,可变参数模板和普通模板是一样的,只是写法上稍有区别,声明可变参数模板时需要在typename或class后面带上省略号...:

template<typename... Types>

其中,...可接纳的模板参数个数是0个及以上的任意数量,需要注意包括0个。我的另一个意思是,如果需要强迫有N个参数模板,那么:

template<typename T1,typename T2, typename... Types>

很好,现在至少要求两个了。

如果我们关心每一个参数是什么,那么,我们一般会选择递归的处理函数模板,举个例子,我们来递归的调用一个有趣的打印函数printRecursive,他是这样做的:

#include <array>
#include <type_traits>
#include <iostream>
​
void print() {}
​
template<typename PrintableCurrent, typename ... PrintableArgs>
void print(const PrintableCurrent& current, const PrintableArgs&... printableArgs)
{std::cout << current << " ";return print(printableArgs...);
}
​
int main()
{print(1, 2, 3, "hello, world", 'h', 9.1234f);
}

看懂这个代码了吗?我们需要一个终止递归的特化函数,还有一个就是我们的主运行函数。

std::common_type

在C++11标准中引入了common_type,在C++14中引入了common_type_t,它主要是用来获取参数的共有类型的,需要注意的,它获取的类型是退化的,因为它内部调用了std::decay。

#include <iostream>
#include <type_traits>
​
int main() {// 定义几个类型using T1 = int;using T2 = double;
​// 使用 std::common_type 推导出公共类型using CommonType = std::common_type<T1, T2>::type;
​// 输出推导结果std::cout << "The common type of int and double is: ";if constexpr (std::is_same_v<CommonType, double>) {std::cout << "double" << std::endl;} else {std::cout << "unknown type" << std::endl;}
​return 0;
}

std::forward

std::forward 是 C++11 引入的一个函数模板,主要用于完美转发(perfect forwarding)。它的作用是根据传递给它的参数类型(左值或右值)转发给函数参数,而不改变它们的类别(即保留其左值或右值特性)。这对于转发参数到其他函数时非常有用,尤其是在实现泛型函数模板时。

std::forward 通过条件地使用 std::move 来实现对右值的转发,而对于左值,它则简单地返回原值。因此,它通常与 std::move 一起使用,以确保右值不会在不需要的地方被拷贝。

#include <iostream>
#include <utility>
​
void func(int& x) {std::cout << "lvalue func, " << x << std::endl;
}
​
void func(int&& x) {std::cout << "rvalue func, " << x << std::endl;
}
​
template <typename T>
void forward_example(T&& arg) {func(std::forward<T>(arg)); // 完美转发
}
​
int main() {int a = 5;forward_example(a);         // 传递左值forward_example(10);        // 传递右值return 0;
}

http://www.ppmy.cn/embedded/140030.html

相关文章

探索Python PDF处理的奥秘:pdfrw库揭秘

文章目录 探索Python PDF处理的奥秘&#xff1a;pdfrw库揭秘1. 背景&#xff1a;为何选择pdfrw&#xff1f;2. pdfrw是什么&#xff1f;3. 如何安装pdfrw&#xff1f;4. 五个简单的库函数使用方法4.1 读取PDF信息4.2 修改PDF元数据4.3 旋转PDF页面4.4 提取PDF中的图片4.5 合并P…

CUDA补充笔记

文章目录 一、不同核函数前缀二、指定kernel要执行的线程数量三、线程需要两个内置坐标变量来唯一标识线程四、不是blocksize越大越好&#xff0c;上限一般是1024个blocksize 一、不同核函数前缀 二、指定kernel要执行的线程数量 总共需要线程数是&#xff1a; 1 * N N个线程…

给机器装上“脑子”—— 一文带你玩转机器学习

目录 一、引言&#xff1a;AI浪潮中的明星——机器学习 二、机器学习的定义与概念 1. 机器学习与传统编程的区别 2. 机器学习的主要任务类型 3. 机器学习的重要组成部分 三、机器学习的工作原理&#xff1a;从数据到模型的魔法之旅 1. 数据收集与预处理——数据是机器的…

解决Windows + Chrome 使用Blob下载大文件时,部分情况下报错net:ERR_FAILED 200 (OK)的问题

背景&#xff1a; 部分线上用户反馈&#xff0c;下载文件会报错&#xff0c;但重启电脑又好了。测试无法复现。遂远程客户&#xff0c;发现在下载超过一定阈值大小的文件时&#xff0c;会报错。 但直接点击下载链接&#xff0c;可以正常下载 查阅代码&#xff0c;以前的写法是…

数据结构(链栈——c语言实现)

链式栈&#xff08;Linked Stack&#xff09;是一种基于链表数据结构实现的栈。它利用链表节点的指针来存储元素&#xff0c;并通过指针的链接关系来维护栈的后进先出&#xff08;LIFO, Last In First Out&#xff09;特性。 链式栈的优点 动态大小&#xff1a; 链式栈…

Oracle数据库安全扫描1158/3938端口出现弱SSL加密算法解决方法之一

问题复述 某国企项目现场反应安全扫描出部署某历史项目的Windows服务器上的1158及3938两个端口出现了弱SSL加密算法漏洞&#xff0c;要求整改。 经过核实&#xff0c;该Windows服务器上部署了tomcat与Oracle 11g数据库&#xff0c;其中1158和3938两个端口均为Oracle数据库所使…

使用Python和OpenCV连接并处理IP摄像头视频流

使用Python和OpenCV连接并处理IP摄像头视频流 随着智能设备的发展&#xff0c;越来越多的家庭和企业开始使用IP摄像头进行安全监控或远程查看。这些摄像头通常可以通过网络访问&#xff0c;提供了丰富的功能&#xff0c;如实时视频流、云台控制等。本文将详细介绍如何利用Pyth…

设计模式之 桥接模式

桥接模式&#xff08;Bridge Pattern&#xff09;是一种结构型设计模式&#xff0c;其核心思想是将抽象部分和实现部分分离&#xff0c;使它们可以独立地变化。通过桥接模式&#xff0c;抽象部分和实现部分可以独立扩展&#xff0c;从而避免了继承层次过深和高耦合的问题。 桥…