std::variant快速上手
std::variant
是 C++17 引入的一种类型安全的联合体,用来存储多个可能类型中的一种值,且保证使用时的类型安全。相比于传统的 union
,std::variant
不仅能够存储不同类型的值,还能自动管理复杂类型的构造与析构。
如何快速上手 std::variant
。
1. 定义 std::variant
使用 std::variant
可以定义一个变量,该变量可以持有多种不同类型的值,但一次只能存储一种。
#include <iostream>
#include <variant>
int main() {
std::variant<int, float, std::string> v; // v 可以是 int、float 或 std::string
// 设置为 int 类型
v = 42;
std::cout << std::get<int>(v) << std::endl;
// 设置为 float 类型
v = 3.14f;
std::cout << std::get<float>(v) << std::endl;
// 设置为 std::string 类型
v = "Hello, std::variant!";
std::cout << std::get<std::string>(v) << std::endl;
return 0;
}
2. 访问 std::variant
的值
std::variant
的值可以通过 std::get<type>
或 std::get<index>
访问。
std::variant<int, float, std::string> v = 42;
// 使用类型访问
std::cout << std::get<int>(v) << std::endl;
// 使用索引访问,0 表示第一个类型
std::cout << std::get<0>(v) << std::endl;
注意:
- 如果你尝试访问的类型与当前存储的类型不匹配,程序会抛出
std::bad_variant_access
异常。
std::variant<int, float, std::string> v = 42;
try {
std::cout << std::get<float>(v); // 当前不是 float 类型,会抛出异常
} catch (const std::bad_variant_access& e) {
std::cout << "Wrong type access: " << e.what() << std::endl;
}
3. 检查当前类型
你可以使用 std::holds_alternative<T>(variant)
来判断 std::variant
当前是否持有某种类型。
if (std::holds_alternative<int>(v)) {
std::cout << "v holds an int" << std::endl;
}
4. 访问当前存储类型的索引
你可以使用 v.index()
获取当前存储值的类型在 std::variant
中的索引。
std::cout << "Index: " << v.index() << std::endl; // 0 表示 int,1 表示 float,依次类推
5. 使用 std::visit
访问 std::variant
std::visit
是 std::variant
的一个访问工具,它使用一个可调用对象(如 lambda 表达式或函数)来访问 std::variant
的值,而无需手动判断当前的类型。
#include <iostream>
#include <variant>
#include <string>
int main() {
std::variant<int, float, std::string> v = "Hello";
std::visit([](auto&& arg) {
std::cout << arg << std::endl; // 打印不同类型的值
}, v);
return 0;
}
6. 常见应用场景
- 存储多种类型的值:当需要一个变量存储多种可能的类型时,
std::variant
比union
更灵活和安全。 - 事件系统:可以使用
std::variant
来构建一种通用的事件系统,不同事件类型对应不同的variant
。 - 解析数据:如解析 JSON 或 XML 等格式化数据,数据字段可能是不同的类型。
小结
std::variant
可以存储多个类型之一,并且类型安全。- 通过
std::get<type>
或std::get<index>
访问值。 - 使用
std::holds_alternative
判断存储类型,使用std::visit
处理不同类型的值。
std::monostate
是 C++17 引入的一种特殊类型,通常用于与std::variant
一起使用。std::monostate
本身没有任何成员或功能,主要作用是用作默认的、无效的状态。当std::variant
没有匹配到任何实际类型时,可以使用std::monostate
作为占位符。
std::variant
是 C++17 引入的一个类型,用于表示一个值可以是多个类型中的任意一种。当您将std::variant
作为函数参数时,它可以接受构造函数中定义的任意一种类型的输入。
std::variant函数参数
首先,让我们定义一个 std::variant
,例如:
#include <variant>
#include <string>
#include <iostream>
using MyVariant = std::variant<int, double, std::string>;
在这个例子中,MyVariant
可以接受三种类型的值:int
、double
和 std::string
。
函数参数
您可以将 std::variant
作为函数参数,接受这些类型的任意一种。例如:
void processVariant(const MyVariant& value) {
std::visit([](auto&& arg) {
std::cout << "Processing: " << arg << std::endl;
}, value);
}
在这个函数中,使用 std::visit
可以访问 variant
中存储的值,并根据实际类型执行相应的操作。
调用示例
您可以通过多种方式调用这个函数,传入不同类型的值:
int main() {
MyVariant v1 = 42; // int
MyVariant v2 = 3.14; // double
MyVariant v3 = std::string{"Hello"}; // std::string
processVariant(v1); // 输出: Processing: 42
processVariant(v2); // 输出: Processing: 3.14
processVariant(v3); // 输出: Processing: Hello
return 0;
}
关键点
多态性:
std::variant
提供了一种类型安全的方式来处理多种类型,可以用在函数参数中以接受这些类型。类型安全:使用
std::visit
可确保访问的值是有效的,避免了类型错误。构造和赋值:您可以直接使用各种支持的类型初始化
std::variant
,并在需要时将其传递给函数。
std::variant
可以作为函数参数,接受多种类型的值,这些类型是在定义std::variant
时指定的。- 通过
std::visit
,您可以安全地处理存储在std::variant
中的不同类型的值。 - 这种机制为处理异构数据提供了灵活性和安全性。
std::monostate使用场景:
作为
std::variant
的默认类型:std::variant
是一个可以保存多个不同类型的值的容器。std::monostate
可以作为std::variant
的第一个类型,以处理变体未初始化的情况。处理空状态: 通过将
std::monostate
添加到std::variant
中的类型列表,可以让std::variant
有一个明确的“空”状态。
#include <iostream>
#include <variant>
int main() {
// 定义一个 std::variant,可以保存 int、double 或 std::monostate
std::variant<std::monostate, int, double> var;
// 初始时,variant 包含的是 std::monostate
if (std::holds_alternative<std::monostate>(var)) {
std::cout << "Variant is in the default state (monostate)\n";
}
// 赋值一个 int 类型
var = 42;
if (std::holds_alternative<int>(var)) {
std::cout << "Variant holds an int: " << std::get<int>(var) << "\n";
}
return 0;
}
Variant is in the default state (monostate)
Variant holds an int: 42
std::monostate
的特点:
- 类型安全:它是一个有类型的空状态,并且可以在
std::variant
中使用时避免无效状态。 - 支持比较运算:
std::monostate
支持相等比较(==
)和小于比较(<
),因此可以用于比较std::variant
中的状态。 - 默认无效状态:当
std::variant
初始化时,没有赋值任何有效类型,std::monostate
可以表示这种状态。
std::get_if<>
是 C++17 引入的一个函数,通常用于与std::variant
一起使用。它的作用是安全地访问std::variant
中存储的某种类型的值,并返回指向该类型值的指针。如果std::variant
中存储的不是该类型,则返回nullptr
。这个函数避免了直接使用std::get<>
可能导致的异常抛出。
作用和使用场景:
- 类型安全的访问:
std::get_if<>
可以在访问std::variant
时避免异常,通过返回指针的方式来安全判断实际存储的类型。 - 避免抛异常:
std::get<>
在类型不匹配时会抛出std::bad_variant_access
异常,而std::get_if<>
返回nullptr
,因此可以在不使用异常处理的情况下检测类型。
std::get_if<>
主要有两种形式:
对于
std::variant
非常量对象的访问:T* std::get_if<T>(&variant);
这将返回一个指向
T
类型的指针,如果variant
中存储的不是T
类型,则返回nullptr
。对于
std::variant
常量对象的访问:const T* std::get_if<T>(const &variant);
如果是常量对象,返回的是
const T*
指针。否则返回nullptr
。
示例
#include <iostream>
#include <variant>
int main() {
std::variant<int, double, std::string> var = 42;
// 使用 get_if<> 来安全访问 int 类型
if (int* value = std::get_if<int>(&var)) {
std::cout << "Variant holds an int: " << *value << "\n";
} else {
std::cout << "Variant does not hold an int\n";
}
// 尝试访问 double 类型,会返回 nullptr
if (double* value = std::get_if<double>(&var)) {
std::cout << "Variant holds a double: " << *value << "\n";
} else {
std::cout << "Variant does not hold a double\n";
}
return 0;
}
输出:
Variant holds an int: 42
Variant does not hold a double
总结:
std::get_if<>
提供了类型安全且不抛异常的访问方式。- 如果匹配类型,它返回指向存储值的指针;否则返回
nullptr
。 - 有两个版本:一个用于常量访问,另一个用于非常量访问。
std::variant快速上手的更多相关文章
- 【opencv入门篇】 10个程序快速上手opencv【下】
导言:本系列博客目的在于能够在vs快速上手opencv,理论知识涉及较少,大家有兴趣可以查阅其他博客深入了解相关的理论知识,本博客后续也会对图像方向的理论进一步分析,敬请期待:) 上篇传送:http: ...
- 【opencv入门篇】 10个程序快速上手opencv【上】
导言:本系列博客目的在于能够在vs快速上手opencv,理论知识涉及较少,大家有兴趣可以查阅其他博客深入了解相关的理论知识,本博客后续也会对图像方向的理论进一步分析,敬请期待:) PS:官方文档永远是 ...
- Markdown 语法的超快速上手
本文支持WTFPL协议,因此你想往哪转就往哪转. Why markdown? Markdown是一种可以使用普通文本编辑器编写的标记语言,通过简单的标记语法,它可以使普通文本内容具有一定的格式. Ma ...
- Pandas快速上手(一):基本操作
本文包含一些 Pandas 的基本操作,旨在快速上手 Pandas 的基本操作. 读者最好有 NumPy 的基础,如果你还不熟悉 NumPy,建议您阅读NumPy基本操作快速熟悉. Pandas 数据 ...
- 快速上手pandas(上)
pandas is a fast, powerful, flexible and easy to use open source data analysis and manipulation to ...
- 【Python五篇慢慢弹】快速上手学python
快速上手学python 作者:白宁超 2016年10月4日19:59:39 摘要:python语言俨然不算新技术,七八年前甚至更早已有很多人研习,只是没有现在流行罢了.之所以当下如此盛行,我想肯定是多 ...
- 快速上手Unity原生Json库
现在新版的Unity(印象中是从5.3开始)已经提供了原生的Json库,以前一直使用LitJson,研究了一下Unity用的JsonUtility工具类的使用,发现使用还挺方便的,所以打算把项目中的J ...
- [译]:Xamarin.Android开发入门——Hello,Android Multiscreen快速上手
原文链接:Hello, Android Multiscreen Quickstart. 译文链接:Hello,Android Multiscreen快速上手 本部分介绍利用Xamarin.Androi ...
- [译]:Xamarin.Android开发入门——Hello,Android快速上手
返回索引目录 原文链接:Hello, Android_Quickstart. 译文链接:Xamarin.Android开发入门--Hello,Android快速上手 本部分介绍利用Xamarin开发A ...
- 快速上手seajs——简单易用Seajs
快速上手seajs——简单易用Seajs 原文 http://www.cnblogs.com/xjchenhao/p/4021775.html 主题 SeaJS 简易手册 http://yslo ...
随机推荐
- httpclient,轻量级idea集成测试工具
优点:不用新开一个网页,具有测试数据保存功能,不需要配置即用(对比swagger) 不会特别占内存(对比postman) 使用方法:idea中安装插件 controller方法中点击 选择对应 ...
- 打开电脑属性 设置 windows
组合键:win+R,输入sysdm.cpl,然后运行. 右键"此电脑",选择属性,然后点击高级系统设置. 组合键:win+Pause/Break. 在命令提示符中输入SystemP ...
- docker 网络互通
自定义网络 查看所有的docker网络 网络模式 [root@docker ~]# docker network ls NETWORK ID NAME DRIVER SCOPE a4d70d5796e ...
- CentOS-7离线安装net-tools
1.下载相关安装包 CentOS-7 所有rpm包的仓库地址:https://vault.centos.org/7.9.2009/os/x86_64/Packages/ net-tools-2.0-0 ...
- 【Node】下载安装(Linux)
不要使用源码包安装!!!编译时间太长!! 不要使用源码包安装!!!编译时间太长!! 不要使用源码包安装!!!编译时间太长!! 使用Node源码包安装 这里使用的是源码包安装 Node官网地址:也不是官 ...
- 基于MybatisPlus的简单分页查询和条件分页查询
分页查询 分析: 分析文档要求 查看前端传递给后台的参数 分析参数进行编码 后台返回给前端的数据 思路 浏览器 - > Controller层 - > Service层 - > Ma ...
- 为baselines算法库安装mujoco环境支持——ubuntu 20.04安装MuJoCo2.1.1
下载开源版本的mujoco二进制文件: wget https://github.com/deepmind/mujoco/releases/download/2.1.1/mujoco-2.1.1-lin ...
- [USACO22FEB] Paint by Rectangles P 题解
前言 没用线段树的小常数.小短码. 题目链接:洛谷. 题意简述 给出 \(n\) 个平行于坐标轴的矩形,各边所在直线互不重合,钦定最外面为白色,对这个平面图黑白染色,分别求黑色块数和白色块数. 题目分 ...
- 增强用户体验:2个功能强大的.NET控制台应用帮助库
前言 对于.NET开发者而言,构建控制台应用程序时,如何提升用户交互的流畅性和满意度,是一个持续探索与优化的话题.今天大姚给大家分享2个功能强大的.NET控制台应用帮助库,希望可以帮助大家能够快速的构 ...
- 白鲸开源 DataOps 平台加速数据分析和大模型构建
作者 | 李晨 编辑 | Debra Chen 数据准备对于推动有效的自助式分析和数据科学实践至关重要.如今,企业大都知道基于数据的决策是成功数字化转型的关键,但要做出有效的决策,只有可信的数据才能提 ...