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

#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_typestd::variant<std::string, int, float> v3{std::in_place_index<1>, 66}; // 使用std::in_place_indexstd::cout << v1.index() << std::endl; //当前属于的类型 输出: 0std::cout << std::get<int>(v1) << std::endl; // 输出: 42std::cout << std::get<std::string>(v2) << std::endl; // 输出: Hellostd::cout << std::get<int>(v3) << std::endl; // 输出: 66return 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 0000000000000000std::cout << *(std::get_if<std::string>(&v)) << std::endl; // 输出: hello// 使用std::visit访问std::visit([](auto&& arg) { std::cout << arg << std::endl; }, v); // 输出: Helloreturn 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.rhkb.cn/news/456135.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue2 el-select赋值无效(无法选中)

背景&#xff1a;点击添加明细时&#xff0c;el-table会新增一条数据&#xff0c;其中&#xff0c;存货原申购用途 会根据 费用承担事业部 下拉框的值改变而改变&#xff0c;所以每次费用承担事业部发生变化时&#xff0c;都需要清空存货原申购用途的值 最开始是直接这样写的&a…

基于Java(SSM框架)+MySQL开发的小型英语学习网站

一、需求分析 英语已经越来越凸显其重要性。大学生一般都需要考CET-4或者CET-6&#xff0c;对于程序员&#xff0c;如果没有扎实的英语基础&#xff0c;看有些API文档也比较费力。生活中处处存在英语&#xff0c;也越来越体现英语的重要性&#xff0c;如何高效学习英语成了关键…

Openlayers高级交互(7/20):点击某点弹出窗口,自动播放视频

在使用 OpenLayers 构建 WebGIS 应用程序时,如果你想在地图上嵌入视频,通常的做法是将视频作为覆盖层(Overlay)添加到地图上。这里是一个示例,点击某点弹出窗口,自动播放视频。 效果图 专栏名称内容介绍Openlayers基础实战 (72篇)专栏提供73篇文章,为小白群体提供基础…

Vxe UI vue vxe-table 虚拟树表格的使用,流畅的渲染万级数据树结构表格

Vxe UI vue vxe-table 虚拟树表格的使用&#xff0c;流畅的渲染万级数据树结构表格 代码 普通树表格&#xff0c;一般存数据库里都是平级数据&#xff0c;vxe-table 的树渲染这就非常友好了&#xff0c;只有带有父子id关联的数组&#xff0c;就可以自动渲染树表格。 <te…

用 Vue 打造高效 Gherkin 自动化测试脚本编写工具

之前曾撰写过一篇有关运用 Pytest - BDD 框架开展自动化测试的文章。行为驱动开发&#xff08;BDD&#xff09;因着重于以业务需求和用户行为作为导向来编写测试脚本&#xff0c;故而广受关注。Gherkin 作为 BDD 中常用的语言&#xff0c;用于描述测试场景与步骤&#xff0c;具…

C#学习笔记(五)

C#学习笔记&#xff08;五&#xff09; 第 三 章 基本语句以及语法一、控制台的基本语句使用1. 方法重载2. 输入输出3.字符串格式化 二、赋值运算符、算数运算符、比较运算符三、数据类型转换常用方法使用、比较和选择1. 自动类型转换(隐式转换)2. 强制类型转换2.1 数值类型之间…

k8s-service详解

Service介绍 在kubernetes中&#xff0c;pod是应用程序的载体&#xff0c;我们可以通过pod的ip来访问应用程序&#xff0c;但是pod的ip地址不是固定的&#xff0c;这也就意味着不方便直接采用pod的ip对服务进行访问。 为了解决这个问题&#xff0c;kubernetes提供了Service资源…

COVON全意卫生巾,轻薄透气,绵柔速干,马来西亚热销中

随着女性健康意识的提高&#xff0c;卫生巾作为女性日常生活中的必需品&#xff0c;其品质和舒适度越来越受到关注。今天&#xff0c;我们要为大家介绍一款来自马来西亚热销的卫生巾——COVON全意卫生巾&#xff0c;以其轻薄透气、绵柔速干的特点&#xff0c;赢得了广大女性的喜…

故障诊断 | CNN-GRU卷积神经网络-门控循环单元组合模型的故障诊断(Matlab)

效果一览 文章概述 故障诊断 | CNN-GRU卷积神经网络-门控循环单元组合模型的故障诊断(Matlab) 源码设计 %% CNN-GRU多特征分类预测

ORA-12170: TNS:Connect timeout occurred

tnsping xxx通 telnet xxx 端口通 sqlplus xxx/xxx提示ORA-12170: TNS:Connect timeout occurred 沟通了解到&#xff0c;目标端为oracle rac两节点&#xff0c;目前只开通了scan ip的端口策略。 处理办法&#xff1a; 开通两个vip的端口策略。 由于本次连接只是测试用的…

CSS综合案例——新闻详情

一、知识点 1、文字颜色 属性名&#xff1a;color 属性值&#xff1a; 颜色表示方式属性值说明使用场景颜色关键字颜色英文单词red,green,blue学习测试rgb表示法rg(r,g,b)r,g,b表示红绿蓝三原色&#xff0c;取值0-255了解rgba表示法rgba(r,g,b,a)a表示透明度&#xff0c;取…

Android 自定义 Dialog 实现列表 单选,多选,搜索

前言 在Android开发中&#xff0c;通过对话框让用户选择&#xff0c;筛选信息是很方便也很常见的操作。本文详细介绍了如何使用自定义 Dialog、RecyclerView 以及自定义搜索框 来实现选中状态和用户交互&#xff0c;文中大本分代码都有明确注释&#xff0c;主打一个简单明了&a…

JS | 如何使用 JavaScript 实现图片懒加载的淡入效果?

在现代的网页设计中&#xff0c;为了提高用户体验和网站性能&#xff0c;图片懒加载已经成为一个常见的技术。图片懒加载可以减少初始加载时间&#xff0c;延迟加载图片直到用户滚动到它们所在的位置。另外&#xff0c;为了进一步提升用户体验&#xff0c;添加淡入效果可以使页…

【忍无可忍,无需再忍】永久解决xshell or xftp 更新问题

1 背景介绍 提示“要继续使用此程序,您必须应用最新的更新或使用新版本”&#xff0c;笔者版本是xshell 6 距离一段时间不使用&#xff0c;或者遇到更新场景&#xff0c;总是会弹出这个框&#xff0c;实在是忍无可忍&#xff0c;无需再忍。 2 思路介绍 笔者上一篇关于如何解…

学习的内核,如何更好的学习呢?

文章目录 三步学习法起因&#xff1a;三步学习法是什么&#xff1f;三步学习法为什么&#xff1f;我自己的实例 三步学习法应该怎么办&#xff1f;总结&#xff1a; 三步学习法 起因&#xff1a; 今天在学习黑马的java设计模式&#xff0c;我会觉得我的学习进度很慢&#xff0…

MAVlink协议 部分通用消息集解析

文章目录 MAVLink是一种非常轻量级的消息传输协议, 用于地面控制终端&#xff08;地面站&#xff09;与无人机之间 (以及机载无人机组件之间) 进行通信&#xff0c; 为一种设计用于资源受限系统及带宽受限链路的二进制遥测协议。 HEARTBEAT 检测信号消息显示系统或组件存在并正…

【32】C++流

C流 IO: 向设备输入数据和输出数据 C的IO流 设备: 文件控制台特定的数据类型(stringstream) c中,必须通过特定的已经定义好的类, 来处理IO(输入输出) 读写文件&#xff1a;文件流 文件流: 对文件进行读写操作 头文件: <fstream> 类库: ifstream 对文件输入&am…

C#基础知识-枚举

目录 枚举 1.分类 1.1普通枚举 1&#xff09;默认情况 2&#xff09;指定起始值 1.2标志枚举&#xff08;Flag Enum&#xff09; 位运算符与标志枚举 1&#xff09;组合标志 2&#xff09;检查标志 2.枚举与不同类型之间的转换 1&#xff09;枚举->整型 2&#…

深度学习调参大法

目录 trick 1&#xff1a;深度学习调参核心点trick 2&#xff1a;关于 深度学习Model选型问题trick 3&#xff1a;关于数据trick 4&#xff1a;关于调参 4.1 关于 Loss function 调参策略4.2 关于 Learning rate 和 batch size 调参策略4.3 关于 Epoch number 和 early stoppi…

数据结构模板代码合集(不完整)

P3368 【模板】树状数组 2 #include <bits/stdc.h> using namespace std; const int maxn 5e5 7;int n, m, s, t; int ans; int a[maxn]; struct node{int l, r;int num; }tr[maxn * 4];void build(int p, int l, int r){tr[p] {l, r, 0};if(l r){tr[p].num a[l];r…