当前位置: 首页 > news >正文

【C++】C++17结构化绑定、std::optional、std::variant、std::any

二十二、C++17中的结构化绑定、std::optional、std::variant、std::any

本部分是一个小系列,介绍C++17中新引入的、用来解决各种不同返回情况的、标准库新组件。

1、C++的结构化绑定
结构化绑定structured bindings是C++17中引入的一项特性,它允许开发者方便地从元组、结构体或数组中解包数据到单独的变量。是在元组(tuple)和对组(pairs)的基础上,新扩展的一种处理多返回值的新方法。

下面例子是我用一个函数返回一个tuple元组,我是如何取出元组中的各个元素的,也就是如何解包的:

其实在C++中处理多个返回值,我这篇博文 【C++】C++中如何处理多返回值、C++中的模板、宏_如何在c 十十 中处理返回值?-CSDN博客 已经介绍过了好几种方法,感兴趣的同学可以自行查看。这里的前两种方式不限于C++标准的版本,但是第三种结构化绑定只适用于C++17标准。所以要使第三种解包方式顺利通过编译,就得在visual studio的property页面里面设置为C++17标准,如上右图所示。

如果说本部分处理的都是确定的、多个返回值,那么对于不确定个数的返回值如何处理呢?就是下面的小标2如何处理optional数据。

2、如何存储可能存在也可能不存在的数据:std::optional
对于返回值不确定时,我们就得用std::optional了。std::optional也是C++17标准中新引进的模板类类型,用于处理那些可能存在也可能不存在的数据。要使用std::optional,首先需要包含头文件。

比如我们现在要写一个函数,这个函数的功能是读取一个文件,那这个文件是否存在?数据是否是我们期望的格式?函数是否正常读取了这个文件?此时这个函数的返回就是一个不确定的数据,可能有返回数据,也可能没有返回数据,也可能需要返回多个数据。
如果正常读取了,那就不用返回什么;如果文件就不存在,那就得返回一个能说明文件是存在还是不存在的东西;如果文件格式不正确,那得返回一个格式不正确的说明。所以函数的返回不是很确定的这种场景,就得用std::optional了。

我们先写一个不用optional的函数:

这种写法就很被动。当读取不成功时,我们也不知道什么原因,是路径错了还是格式错了,还是路径格式都没错,只是文件里面确实就是没数据,所以啥也没读出来。下面我们看看使用optional能多大程度解决这些问题:

可见使用optional代码要稍微清晰一些了,如果文件没打开或者文件格式没对,就没读到文件,我们可以用value_or解释一下返回的空字符是怎么回事。 下面是optional操作符的简单介绍:

3、如何在一个变量中存储多种类型的数据:std::variant
这也是C++17新标准库中提供给我们的模板类:std::variant。它的作用是让我们不用担心处理的确切数据类型。
我们要做的就是指定一个叫做std::variant的类型,然后列出它可能的数据类型。比如你正在解析一个文件,你不确定这是一个字符串还是一个整数还是浮点数或者是布尔数,你就把所有可能的类型都列出来。下面是variant的操作符:

下面我们用代码来说明variant的用法:

从上图variant类型对象的大小可以看出,variant对象的大小是所有类型的大小之和。确切的说是内存对齐后的大小之和。可见,variant是结构体或者类包装而来的。就是其实每种类型它都是分配了对应的内存空间了的。

而与variant非常相似的union可并不是这样的,union分配的内存是所有可能类型数据中的最大那个类型的空间大小。所以variant和union是有本质区别的。也就是说variant是将所有可能的数据类型存储为单独的变量、作为单独的成员。而union则是所有可能的数据类型共享一个内存空间。

可见variant是给我们创建了一个结构体或类,它只是将这可能的多种数据类型存储成那个类或者结构体的成员。
也所以,从技术上讲,union更有效率,但variant更加类型安全,不会造成未定义行为。

前面读取文件的例子,我们使用optional也没有很完美的写出清晰的逻辑,现在我用variant再写这个例子:

此时是不是逻辑就清晰很多、代码也优雅很多!这就是variant的使用场景。

4、如何存储任意类型的数据:std::any
就是在C++单个变量中存储任意类型的数据:std::any,这也是C++17的全新处理方式。
std::variant是需要列出你可能用到的所有类型。而std::any是不需要声明任何类型:

可见,any类型的变量在声明和初始化时,就可以完全不用管变量的类型,只有当你要解码这个变量时才需要这个变量的真正的类型。

variant让我们列出所有可能用到的类型,然后它背后是悄悄生成一个包含了所列的类型的结构体或者类,所以variant是类型安全的。

而从any的源码看,对于小类型small type(就是最底层的那些类型),any的底层和variant是完全相同的。对于大类型(就是复杂的类型),any会动态分配内存,使用void*存储到大存储空间。动态分配内存不利于性能。就是说,如果你在小类型上,比如int, float,甚至vector类或者类似的比如math库等等,使用variant或者any都一样,因为它们都是相同的工作原理。但是如果你需要更多的存储空间,any会动态分配,但variant不会。话说回来就是variant在处理较大数据时会执行得更快,因为避免了动态分配内存。

最后再展示一下any是如何动态分配内存的:

超过32个字节,any就开始动态分配内存了。所以,any是来搞笑的吗?一般不建议经常使用。

相关文章:

【C++】C++17结构化绑定、std::optional、std::variant、std::any

二十二、C17中的结构化绑定、std::optional、std::variant、std::any 本部分是一个小系列,介绍C17中新引入的、用来解决各种不同返回情况的、标准库新组件。 1、C的结构化绑定 结构化绑定structured bindings是C17中引入的一项特性,它允许开发者方便地…...

C#的起源。J++语言的由来?J#和J++傻傻分不清?

C#的起源 C#读音是C Sharp, 它是微软为了对抗Java而生,最早是J,效率比Java还好,后来被Sun公司起诉J破坏了平台无关性,微软重新开发C#. C#和Java一样都定位为中间件语言,用虚拟机执行编译的字节码以达到跨平台目的。从语…...

Flutter 在 对接 google play 时,利用 android studio 可视化生成 已签名的aab包

android studio 可视化生成 aab包 第一 : 先说注意事项 在Flutter项目里面,直接打开当前项目是不行的,不显示相应操作,需要在Android 目录打开,直白点就是直接打开项目里面的Android 目录 不然会出现的一些问题 第一…...

使用web.dev提供的工具实现浏览器消息推送服务

文章目录 前言实现工具和效果实现原理实现过程前端接收用户订阅请求将用户订阅信息更新到后端后端实现接收并保存订阅信息的接口后端实现消息推送的逻辑前言 对于电商独立站来说,新品上架或者促销活动上线及时通知到用户是很重要的,通知的渠道有很多,其中就包括浏览器消息推…...

计算机系统结构为什么用architecture 而不是structure?

architecture本意是建筑学、建筑艺术,其含义就是建筑的样子和背后的设计思想,用于计算机科学可以表达计算机的系统结构和后面的设计原理:它长什么样?它为什么长这样? 与architecture 对应的词是structure &#xff08…...

sqoop问题汇总记录

此篇博客仅记录在使用sqoop时遇到的各种问题。持续更新,有问题评论区一起探讨,写得有不足之处见谅。 Oracle_to_hive 1. main ERROR Could not register mbeans java.security.AccessControlException: access denied ("javax.management.MBeanTr…...

Git 创建新的分支但清空提交记录

有时候需要创建新的分支,但是原有分支的提交非常多,不好区分哪些是创建分支之后的提交。 那么就把原分支的提交全部去掉 要从 分支1 创建 分支2,并确保 分支2 不包含任何提交历史,同时文件与 分支1 的最后一次提交一致&#xff0…...

SQL PRIMARY KEY

SQL PRIMARY KEY 概述 在关系型数据库中,主键(PRIMARY KEY)是一个非常重要的概念。它是表中每一行数据的唯一标识符,用于保证数据的完整性和准确性。本文将详细介绍SQL中的主键,包括其定义、作用、如何创建和修改主键…...

软件测试学习笔记丨Flask操作数据库-对象与数据模型

本文转自测试人社区,原文链接:https://ceshiren.com/t/topic/23440 对象与数据模型 数据模型:是数据特征的抽象,抽象层次上描述了系统的静态特征、动态行为和约束条件,为数据库系统的信息表示与操作提供一个抽象的框架…...

IntelliJ IDEA使用 MybatisX-Generator 插件 自动生成Entity+Mapper+Mapper.xml等代码

一、Intellij安装MybatisX插件: 首先点击 Intellij->Preference->Plugins,然后搜索MybatisX,点击安装: 2 打开数据库 在IntelliJ IDEA 连接Mysql数据库,选择表,点击右键,选择 Mybatis…...

vue中如何为不同功能设置不同的默认打印设置(设置不同的打印机)

浏览器自带的window.print 功能较简单,这里使用LODOP露肚皮打印 以下是vue2示例: 从官网中下载Lodop和C-Lodop官网主站安装包并安装到本地电脑可以全局搜索电脑找到安装文件LodopFuncs.js,也可以直接复制我贴出来的文件 //用双端口加载主JS…...

经纬恒润INTEWORK-VBA新版本正式发布

在汽车电子研发领域,随着开发测试的深入,工程师们常常面临着一个共同的问题:如何高效地在多样化的开发测试场景中切换,并确保不同工具间的紧密协作。不同场景、不同工具的切换与使用给工程师带来高昂的学习成本和前后端信息传递的…...

金蝶云数据集成至MySQL的高效解决方案

金蝶云数据集成至MySQL的高效解决方案 金蝶云星空数据集成到MySQL的技术案例分享 在企业信息化过程中,数据的高效集成和管理是关键环节。本文将聚焦于一个具体的系统对接集成案例:金蝶云星空的数据如何通过轻易云数据集成平台无缝对接到MySQL数据库。本…...

Day02 C++ 环境设置

2024.11.1 C 环境设置 如果您想要设置 C 语言环境,需要确保电脑上有以下两款可用的软件,文本编辑器和 C 编译器。 一、文本编辑器 通过编辑器创建的文件通常称为源文件,源文件包含程序源代码。 C 程序的源文件通常使用扩展名 .cpp、.cp 或…...

AQS是什么

AQS:AbstructQueuedSynchronizer是java.util.concurrent.locks包中的一个类,是多线程同步器,J.U.C包中的多个组件的底层实现都使用到了它。如:Lock、CountDownLatch、Semaphore. 从本质上来说AQS实现了两种机制的锁,排…...

Spring IOC容器简介

Spring IoC(Inversion of Control,控制反转)容器是Spring框架的核心组件之一,负责管理应用程序中的对象及其依赖关系。IoC容器通过依赖注入(Dependency Injection,DI)实现对象的创建、配置和管理…...

【backstopjs】入门安装环境

1.首先全局安装BackstopJS npm install -g backstopjs 安装失败,常见报错&解决办法: 报错: (venv) D:\workspace\Otaku\backstop>npm install -g backstopjs npm warn deprecated inflight1.0.6: This module is not supported, and leaks mem…...

LocalDate 类常用方法详解(日期时间类)

LocalDate 类常用方法详解 LocalDate 是 Java 8 引入的日期时间API中的一个类,用于表示不含时间和时区的日期(年、月、日)。以下是一些常用的 LocalDate 方法: 创建 LocalDate 实例 now():获取当前日期 LocalDate t…...

kmp desktop实现excel预览

先将excel转paf https://blog.csdn.net/qq_42761569/article/details/121699594 package utilimport com.aspose.cells.License import com.aspose.cells.PdfSaveOptions import com.aspose.cells.Workbook import com.geolo.desktop.common.utils.LogUtils import java.io.Fi…...

OB_GINS_day3

这里写目录标题 实现当前状态初始化实现预积分的初始化由于此时preintegration_options 是3(也就是考虑odo以及earth rotation)为预积分的容器添加需要积分的IMU积分因子接下来是添加新的IMU到preintegration中 实现当前状态初始化 这个state_curr的主要…...

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

7.4.分块查找

一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...

mongodb源码分析session执行handleRequest命令find过程

mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...

安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件

在选煤厂、化工厂、钢铁厂等过程生产型企业,其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进,需提前预防假检、错检、漏检,推动智慧生产运维系统数据的流动和现场赋能应用。同时,…...

DBAPI如何优雅的获取单条数据

API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践

6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作

一、上下文切换 即使单核CPU也可以进行多线程执行代码,CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短,所以CPU会不断地切换线程执行,从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

浅谈不同二分算法的查找情况

二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况&#xf…...

关于easyexcel动态下拉选问题处理

前些日子突然碰到一个问题,说是客户的导入文件模版想支持部分导入内容的下拉选,于是我就找了easyexcel官网寻找解决方案,并没有找到合适的方案,没办法只能自己动手并分享出来,针对Java生成Excel下拉菜单时因选项过多导…...

在 Spring Boot 中使用 JSP

jsp&#xff1f; 好多年没用了。重新整一下 还费了点时间&#xff0c;记录一下。 项目结构&#xff1a; pom: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://ww…...