「C/C++」C++17 之 std::variant 安全的联合体(变体)

news2024/11/26 2:54:36

#1024程序员节|征文#
在这里插入图片描述
在这里插入图片描述

✨博客主页
何曾参静谧的博客
📌文章专栏
「C/C++」C/C++程序设计
📚全部专栏
「VS」Visual Studio「C/C++」C/C++程序设计「UG/NX」BlockUI集合
「Win」Windows程序设计「DSA」数据结构与算法「UG/NX」NX二次开发
「QT」QT5程序设计「File」数据文件格式「PK」Parasolid函数说明

目录

    • std::variant详解
      • 1. 引用头文件
      • 2. 注意事项
      • 3. 函数构造
      • 4. 对象初始化
      • 5. 元素访问
      • 6. 迭代器(不适用)
      • 7. 容器(不适用)
      • 8. 修改器
      • 9. 元素比较
      • 10.其他用法
        • 总结
      • 应用场景

std::variant详解

在这里插入图片描述
在这里插入图片描述

1. 引用头文件

std::variant是C++17引入的一种类型安全的联合体,用于存储多个可能类型中的一种值。要使用std::variant,首先需要包含头文件#include <variant>

#include <variant>

2. 注意事项

  • std::variant不允许存储引用、数组或void类型。
  • std::variant没有空的状态,每个构造好的std::variant对象至少调用了一次构造函数。
  • 如果std::variant的第一个类型没有默认构造函数,那么调用std::variant的默认构造函数会导致编译错误。此时,可以使用std::monostate作为第一个类型来确保std::variant能默认构造。
  • 使用std::variant时,如果存储的类型有可能在语义上重叠或不明确(如std::variant<int, float>),需要特别注意操作和类型检查的准确性。

3. 函数构造

std::variant的构造函数允许通过直接赋值、std::in_place_type或std::in_place_index等方式进行初始化。

#include <iostream>
#include <variant>
#include <string>

int main() {
    std::variant<int, double, std::string> v1 = 42; // 直接赋值
    std::variant<std::string, int> v2{std::in_place_type<std::string>, "Hello"}; // 使用std::in_place_type
    std::variant<std::string, int, float> v3{std::in_place_index<1>, 66}; // 使用std::in_place_index

	std::cout << v1.index() << std::endl; //当前属于的类型 输出: 0
    std::cout << std::get<int>(v1) << std::endl; // 输出: 42
    std::cout << std::get<std::string>(v2) << std::endl; // 输出: Hello
    std::cout << std::get<int>(v3) << std::endl; // 输出: 66

    return 0;
}

4. 对象初始化

std::variant对象可以通过直接赋值、构造函数初始化列表等方式进行初始化。

std::variant<int, double, std::string> v = 3.14; // 直接赋值初始化
std::variant<std::string, int> w{"World"}; // 使用构造函数初始化列表

5. 元素访问

访问std::variant中的元素可以使用std::get(variant)或std::get(variant),也可以使用std::visit进行更通用的访问。

#include <iostream>
#include <variant>
#include <string>

int main() {
    std::variant<int, double, std::string> v = "Hello";

    // 使用std::get访问
    try {
        std::cout << std::get<int>(v) << std::endl; // 这将抛出异常
    } catch (const std::bad_variant_access& e) {
        std::cout << "Error: " << e.what() << std::endl; // 输出: Error: bad variant access
    }

	// 使用std::get_if访问
    std::cout << std::get_if<int>(&v) << std::endl; // 输出: nullptr 0000000000000000
    std::cout << *(std::get_if<std::string>(&v)) << std::endl; // 输出: hello

    // 使用std::visit访问
    std::visit([](auto&& arg) { std::cout << arg << std::endl; }, v); // 输出: Hello

    return 0;
}

6. 迭代器(不适用)

std::variant不支持迭代器,因为它不是容器类型,而是存储单一值的类型安全的联合体。

7. 容器(不适用)

虽然std::variant不能作为容器使用,但它可以存储容器类型,如std::vector<int>等。

std::variant<std::vector<int>, std::string> container = std::vector<int>{1, 2, 3};

8. 修改器

std::variant的值可以通过重新赋值进行修改。

std::variant<int, double, std::string> v = 42;
v = 3.14; // 修改为double类型
v = "Hello"; // 修改为std::string类型

9. 元素比较

std::variant不支持直接比较,但可以通过std::visit和适当的比较逻辑来实现比较功能。

#include <iostream>
#include <variant>
#include <string>

bool compare_variants(const std::variant<int, double, std::string>& a, const std::variant<int, double, std::string>& b) {
    return std::visit([](auto&& arg1, auto&& arg2) { return arg1 == arg2; }, a, b);
}

int main() {
    std::variant<int, double, std::string> v1 = 42;
    std::variant<int, double, std::string> v2 = "42"; // 注意这里是字符串类型

    // 比较会失败,因为类型不同
    if (!compare_variants(v1, v2)) {
        std::cout << "v1 and v2 are not equal." << std::endl; // 输出: v1 and v2 are not equal.
    }

    return 0;
}

10.其他用法

    using var = std::variant<int, double, std::string>;
    var value = 1;
    int b = 0;
    b = std::get<int>(value);
总结

std::variant是C++17引入的一种类型安全的联合体,用于存储多个可能类型中的一种值。它提供了类型安全和便利的接口,相比传统的联合体(union)具有更高的安全性和灵活性。std::variant支持多种类型的存储和访问,可以通过std::get、std::visit等方式进行元素访问,同时提供了类型检查和异常处理机制。

应用场景

  1. 配置选项:在开发中,配置项可能需要支持多种数据类型(如整数、字符串、布尔值等)。使用std::variant可以简化配置管理,使得一个配置变量能够存储多种类型的配置值。
  2. 解析器:在编写如JSON解析器或其他形式的解析器时,数据结构可能需要存储不同类型的数据。std::variant提供了一种安全、灵活的方式来存储解析后的数据,从而简化代码并增强其健壮性。
  3. 状态机:在实现状态机时,每个状态可能需要不同类型的数据来描述。std::variant可以用来存储状态相关的数据,使得状态转换和数据处理更加灵活和安全。
  4. 命令模式:在实现命令模式时,如果命令的参数类型多样,std::variant可以作为一个通用的参数容器,提供统一的接口而隐藏实现细节。

通过了解和利用std::variant的这些特点和高级用法,可以在C++中更有效地处理那些需要存储和操作多种数据类型的场景,同时保持代码的整洁性和安全性。


在这里插入图片描述

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

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

相关文章

Web3的去中心化社交网络:区块链技术如何改变互动方式

随着互联网技术的不断进步&#xff0c;社交网络正在经历一场深刻的变革。Web3&#xff0c;作为新一代互联网技术的代表&#xff0c;正通过区块链和去中心化理念改变着我们与他人互动的方式。传统的社交网络通常由大型公司控制&#xff0c;用户数据的集中化管理和隐私问题备受关…

代码随想录(十二)——图论

并查集 并查集主要有三个功能。 寻找根节点&#xff0c;函数&#xff1a;find(int u)&#xff0c;也就是判断这个节点的祖先节点是哪个将两个节点接入到同一个集合&#xff0c;函数&#xff1a;join(int u, int v)&#xff0c;将两个节点连在同一个根节点上判断两个节点是否在…

HarmonyOS 5.0应用开发——文件读写

【高心星出品】 文章目录 文件读写文件操作创建目录删除目录或者文件扫描目录中文件 文本读写写入文本读取文本内容 文件读写文件写入边读边写 文件读写 Core File Kit&#xff08;文件基础服务&#xff09;为开发者提供一套访问和管理应用文件和用户文件的能力。帮助用户更高…

44-RK3588s调试 camera-engine-rkaiq(rkaiq_3A_server)

在RK3588s平台上调试imx415 camera sensor 过程中&#xff0c;已经识别到了camera sensor ID&#xff0c;并且可以拿到raw图和isp处理后的图像&#xff0c;但是isp处理后的图像偏绿&#xff0c;来看查看后台服务发现rkaiq_3A_server没有运行&#xff0c;然后单独运行rkaiq_3A_s…

Linux 宝塔安装(各操作系统命令合集)

由于CentOS官方已全面停止维护CentOS Linux项目&#xff0c;公告指出 CentOS 7和8在2024年6月30日停止技术服务支持&#xff0c;详情见CentOS官方公告。导致CentOS系统源已全面失效&#xff0c;比如安装宝塔等等会出现网络不可达等报错&#xff0c;需要切换源。系统源问题&…

Android 获取OAID

获取OAID 老规矩&#xff0c;直接上&#xff1a; implementation com.huawei.hms:opendevice:6.11.0.300 // 要获取华为vaid 和aaid&#xff0c;还需添加opendevice 依赖implementation(name: oaid_sdk_2.5.0, ext: aar) import android.content.Context; import android.util.…

基于微信小程序的公务员考试信息查询系统+LW示例参考

系列文章目录 1.基于SSM的洗衣房管理系统原生微信小程序LW参考示例 2.基于SpringBoot的宠物摄影网站管理系统LW参考示例 3.基于SpringBootVue的企业人事管理系统LW参考示例 4.基于SSM的高校实验室管理系统LW参考示例 5.基于SpringBoot的二手数码回收系统原生微信小程序LW参考示…

【Android】Kotlin教程(4)

文章目录 1.field2.计算属性3.主构造函数4.次构造函数5.默认参数6.初始化块7.初始化顺序7.延迟初始化lateinit8.惰性初始化 1.field field 关键字通常与属性的自定义 getter 和 setter 一起使用。当你需要为一个属性提供自定义的行为时&#xff0c;可以使用 field 来访问或设置…

可以在线制作的PS网页版来了!

在当今数字化的创意时代&#xff0c;设计领域不断发展与变革&#xff0c;设计师们对于工具的需求也日益多样化和高效化。随着互联网技术的飞速进步&#xff0c;一种全新的设计工具模式应运而生——在线制作的 PS 网页版。它以其独特的优势和便捷性&#xff0c;逐渐成为众多设计…

高德地图如何添加自己店铺的位置信息?

众所周知&#xff0c;创业开店时&#xff0c;地理位置的选择至关重要。一个优越的地理位置不仅能显著提升店铺的可见度&#xff0c;还能有效吸引更多潜在顾客的光顾。而且&#xff0c;为了将店铺的客流量最大化&#xff0c;商家还需在地图平台上准确标注自己的位置信息&#xf…

【黄豆颗粒数据集】黄豆识别 机器视觉 深度学习(含数据集)

一、背景意义 随着全球农业生产的现代化&#xff0c;黄豆&#xff08;大豆&#xff09;作为一种重要的经济作物&#xff0c;广泛用于食品、饲料和工业原料的生产。准确识别和分类黄豆颗粒对于农业生产的管理、质量控制和市场分析具有重要意义。然而&#xff0c;传统的人工分类方…

JavaEE-多线程上

文章目录 线程概述进程/线程多线程的作用JVM关于线程资源的规范关于Java程序的运行原理 并发与并行并发(concurrency)并行(parallellism)并发编程与并行编程 线程的调度策略分时调度模型抢占式调度模型 创建线程线程类分析入门实现线程的第一种方式实现线程的第二种方式 线程的…

论文阅读:三星-TinyClick

《Single-Turn Agent for Empowering GUI Automation》 赋能GUI自动化的单轮代理 摘要 我们介绍了一个用于图形用户界面&#xff08;GUI&#xff09;交互任务的单轮代理&#xff0c;使用了视觉语言模型Florence-2-Base。该代理的主要任务是识别与用户指令相对应的UI元素的屏幕…

Tomcat servlet response关于中文乱码的经验

前言 最近修改老项目项目&#xff0c;使用zuul网关返回的中文内容乱码了&#xff0c;如果使用GBK或者GB2312编码确正常显示&#xff0c;稍微实验了一下&#xff0c;发现里面很多细节&#xff0c;毕竟Springboot对我们做了很多事情&#xff0c;而且当我们使用不同的模式会出现很…

服务器的免密登录和文件传输

在天文学研究中&#xff0c;通常会采用ssh登录服务器&#xff0c;把复杂的计算交给服务器&#xff0c;但是如果你没有进行额外的配置&#xff0c;那么登录服务器&#xff0c;以及和服务器进行文件传输&#xff0c;每次都要输入账号和密码&#xff0c;比较不方便&#xff0c;Win…

Windows Server NTFS磁盘变RAM的处理过程

问题描述 客户服务器的磁盘数据爆满&#xff0c;需要将磁盘进行扩容&#xff0c;因为是虚拟机所以先在虚拟化平台上将原来的磁盘空间改大&#xff0c;再进入系统&#xff0c;在磁盘管理器上将需要扩容的磁盘进行扩展。扩展完后系统报文件系统有问题&#xff0c;扩容的磁盘容量…

No.23 笔记 | WEB安全 - 任意文件漏洞 part 5

本文全面且深入地探讨了文件上传漏洞相关知识。从基础概念出发&#xff0c;清晰地阐述了文件上传漏洞的定义及其产生的本质原因&#xff0c;同时列出了该漏洞成立的必要条件。详细说明了文件上传漏洞可能对服务器控制权、网站安全以及业务运营带来的严重危害。 文中还深入解析了…

[mysql]子查询的概述和分类及单行子查询

子查询引入 查询的基本结构已经给大家了,子查询里面也是有一些新的内容,子查询其实就是在查询中嵌套另一个查询,叫嵌套查询可能大家更容易理解一点..,类似与FOR循环和FOR循环的嵌套,这一章是我们查询的最难的部分,大家 难度是查询的顶峰,多表查询和子查询是非常重要,SQL优化里…

EDA --软件开发之路

之前一直在一家做数据处理的公司&#xff0c;从事c开发&#xff0c;公司业务稳定&#xff0c;项目有忙有闲&#xff0c;时而看下c&#xff0c;数据库&#xff0c;linux相关书籍&#xff0c;后面跳槽到了家eda公司&#xff0c;开始了一段eda开发之路。 eda 是 electric design …

【移动应用开发】使用多媒体--通知/播放音频/视频

目录 一、具体步骤 二、运行截图 1. 开启通知权限 2. 播放音乐 3. 播放视频 三、源代码 1. activity_main.xml 2. activity_video_player.xml 3. activity_notification.xml 4. 一些配置 5. MainActivity 6. VideoPlayerActivity 7. NotificationActivity 8. And…