C++17中std::variant的使用

      可变参数模板类std::variant表示类型安全联合体(type-safe union)。std::variant的实例在任何给定时间要么保存其替代类型之一的值,要么在错误的情况下无值。
      与union一样,如果std::variant保存某个对象类型T的值,则T的对象表示形式将直接在std::variant本身的对象表示形式中分配。不允许std::variant分配额外的(动态)内存,std::variant不会分配堆内存。
      不允许std::variant保存引用、数组或void类型(references, arrays, or the type void)。空的std::variant也是格式错误的。
      允许std::variant多次保存相同类型,并保存相同类型的不同cv限定(cv-qualified versions)版本。
      std::variant允许你以灵活且类型安全的方式处理多种数据类型。std::variant可以存储各种数据类型的值,包括基本类型(int、double等)、用户定义类型(自定义类或结构),甚至其它std::variant。
      使用std::in_place_type或std::in_place_index可对多个值初始化,也可以使用它们在初始化时解决歧义问题。
      和std::optional、std::any一样,std::variant对象是值语义。也就是说,拷贝被实现为深拷贝。
      std::variant持有的值有若干候选项(alternative),这些选项通常有不同的类型。然而,两个不同选项的类型也有可能相同
      初始化和赋值操作都会查找最匹配的选项。如果类型不能精确匹配,可能会发生奇怪的事情。std::variant没有空的状态,这意味着每一个构造好的std::variant对象,至少调用了一次构造函数。默认构造函数会调用第一个选项类型的默认构造函数。如果第一个类型没有默认构造函数,那么调用std::variant的默认构造函数将会导致编译期错误。结构体std::monostate可以处理这种情况。std::monostate可以作为第一个选项类型来保证std::variant能默认构造。

namespace {

template<class T>
auto& operator<<(std::ostream& out, const std::vector<T>& v)
{
	out << "{";
	for (const auto& e : v)
		out << e << " ";
	return out << "}";
}

struct S {
	S(int i) : i(i) {}
	int i;
};

class Derived : public std::variant<int, std::string> { };

} // namespace

int test_variant_init()
{
	std::variant<int, float> var1;
	std::cout << "index: " << var1.index() << ", value: " << std::get<int>(var1) << "\n"; // index: 0, value: 0

	std::variant<std::string, int> var2{ "CHINA" };
	std::cout << "index: " << var2.index() << ", value: " << std::get<std::string>(var2) << "\n"; // index: 0, value: CHINA

	std::variant<std::string, int> var3{ 66 };
	std::cout << "index: " << var3.index() << ", value: " << std::get<int>(var3) << "\n"; // index: 1, value: 66

	std::variant<std::vector<int>, std::string, float> var4{ std::in_place_type<std::string>, "CHINA" };
	std::cout << "index: " << var4.index() << ", value: " << std::get<std::string>(var4) << "\n"; // index: 1, value: CHINA

	std::variant<std::string, std::vector<int>, float> var5{ std::in_place_type<std::vector<int>>, {1, 2, 3, 4, 5} };
	std::cout << "index: " << var5.index() << ", value: " << std::get<std::vector<int>>(var5) << "\n"; // index: 1, value: {1 2 3 4 5 }

	std::variant<std::string, bool, std::vector<std::string>> var6{ std::in_place_index<2>, 5, "hi" };
	std::cout << "index: " << var6.index() << ", value: " << std::get<std::vector<std::string>>(var6) << "\n"; // index: 2, value: {hi hi hi hi hi }

	//std::variant<S> var7; // error C2512: "std::variant<`anonymous-namespace'::S>::variant": 没有合适的默认构造函数可用
	std::variant<std::monostate, S> var7;
	std::cout << "index: " << var7.index() << "\n"; // index: 0
	if (std::holds_alternative<std::monostate>(var7))
		std::cout << "var7 has monostate\n"; // var7 has monostate
	var7 = std::monostate{};

	return 0;
}

      std::variant相关函数
      (1).index:返回存储在std::variant中的数据类型从零开始的索引;
      (2).emplace: 就地(in place)构造std::variant的值;若已存储值,则首先销毁当前存储的值,然后再初始化;
      (3).holds_alternative: 检查std::variant当前是否拥有给定类型;返回bool类型;
      (4).get:从std::variant中检索给定索引或类型(如果类型是唯一的)的值,如果不匹配,则抛出异常;返回存储值的引用
      (5).get_if:获取指向给定索引或类型(如果唯一)的std::variant值的指针,出错时返回nullptr,它的参数是一个指针
      (6).valueless_by_exception:检查std::variant是否处于无效状态;
      (7).std::variant_npos:std::variant处于无效状态时,std::variant的索引值;
      (8).std::swap:交换两个std::variant对象的值;
      (9).operator==, !=, <, <=, >, >=:比较两个std::variant对象;
      std::variant也支持move语义

int test_variant_functions()
{
	std::variant<int, float, std::string> var1{ 66.6f };
	std::cout << "index: " << var1.index() << ", value: " << std::get<float>(var1) << "\n"; // index: 1, value: 66.6

	var1.emplace<2>("CHINA");
	std::cout << "index: " << var1.index() << ", value: " << std::get<std::string>(var1) << "\n"; // index: 2, value: CHINA
	var1.emplace<0>(88);
	std::cout << "index: " << var1.index() << ", value: " << std::get<int>(var1) << "\n"; // index: 0, value: 88

	std::cout << std::boolalpha
		<< "holds int: " << std::holds_alternative<int>(var1)
		<< ", holds string: " << std::holds_alternative<std::string>(var1) << "\n"; // holds int: true, holds string: false

	if (std::holds_alternative<int>(var1))
		std::cout << "var1 type: int\n"; // var1 type : int

	std::variant<std::string, int, float, std::vector<float>> var2;
	var2 = std::get<int>(var1);
	std::cout << "index: " << var2.index() << ", value: " << std::get<int>(var2) << "\n"; // index: 1, value: 88
	var2 = std::get<0>(var1); // <==> var2 = std::get<int>(var1);
	std::cout << "index: " << var2.index() << ", value: " << std::get<int>(var2) << "\n"; // index: 1, value: 88
	std::get<0>(var1) = 99;
	std::cout << "index: " << var1.index() << ", value: " << std::get<int>(var1) << "\n"; // index: 0, value: 99

	try {
		//var2 = std::get<2>(var1);
		var2 = std::get<std::string>(var1);
	} catch (std::bad_variant_access const& ex) {
		std::cout << "exception: " << ex.what() << "\n"; // windows: exception: bad variant access; linux: exception: std::get:wrong index for variant
	}

	std::variant<std::string, std::string> var3;
	std::get<0>(var3) = "China";
	std::cout << "index: " << var3.index() << ", value: " << std::get<0>(var3) << "\n"; // index: 0, value: China
	var3.emplace<1>("Beijing");
	std::cout << "index: " << var3.index() << ", value: " << std::get<1>(var3) << "\n"; // index: 1, value: Beijing

	auto check_value = [](const std::variant<int, float>& v) {
		if (const int* pval = std::get_if<int>(&v))
			std::cout << "variant value: " << *pval << '\n';
		else
			std::cout << "failed to get value" << '\n';
	};

	std::variant<int, float> var4{ 12 }, var5{ 3.f };
	check_value(var4); // variant value: 12
	check_value(var5); // failed to get value

	Derived var6{ "Beijing" };
	std::cout << "index:" << var6.index() << ", value: " << std::get<1>(var6) << "\n"; // index:1, value: Beijing

	std::swap(var4, var5);
	std::cout << "var4 index: " << var4.index() << ", value: " << std::get<1>(var4) << "\n"; // var4 index: 1, value: 3
	std::cout << "var5 index: " << var5.index() << ", value: " << std::get<0>(var5) << "\n"; // var5 index: 0, value: 12

	std::cout << std::boolalpha << "var4 == var5: " << (var4 == var5) << "\n"; // var4 == var5: false

	std::variant<std::string, std::string> var7{ std::in_place_index<1>, "China" }, var8;
	std::cout << "index: " << var7.index() << ", value: " << std::get<1>(var7) << "\n"; // index: 1, value: China
	var7.emplace<0>("Bejing");
	std::cout << "index: " << var7.index() << ", value: " << std::get<0>(var7) << "\n"; // index: 0, value: Bejing

	var8 = std::move(var7);
	std::cout << "index: " << var7.index() << ", value: " << std::get<0>(var7) << "\n"; // index: 0, value:
	std::cout << "index: " << var8.index() << ", value: " << std::get<0>(var8) << "\n"; // index: 0, value: Bejing

	return 0;
}

      执行结果如下图所示:

      GitHub:https://github.com/fengbingchun/Messy_Test

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【音视频基础】AVI文件格式

AVI文件采用的是RIFF文件结构方式。波形音频wave&#xff0c;MIDI和数字视频AVI都采用这种格式存储。 AVI文件的整体结构如下图所示 构造RIFF文件的基本单元叫做数据块&#xff08;Chunk&#xff09;&#xff0c;每个数据块包含3个部分 4字节的数据块标记&#xff08;或者叫…

动 态 规 划

一、&#xff08;what&#xff1f;&#xff09; 二、&#xff08;why&#xff1f;&#xff09; 三、&#xff08;how&#xff1f;&#xff09; 四、典型例题分析&#xff1a; 例题1&#xff1a;神奇的兔子序列 输入&#xff1a;月数 输出&#xff1a;兔子数 思路&#xff1…

基于机器学习的居民消费影响因子分析预测

项目视频讲解: 基于机器学习的居民消费影响因子分析预测_哔哩哔哩_bilibili 主要工作内容: 完整代码: import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns import missingno as msno import warnings warnings.filterwarnin…

Python------列表 集合 字典 推导式(本文以 集合为主)

推导式&#xff1a; 推导式comprehensions&#xff08;又称解析式&#xff09;&#xff0c;是Python的一种独有特性。推导式是可以从一个数据序列 构建 另一个 新的数据序列&#xff08;一个有规律的列表或控制一个有规律列表&#xff09;的结构体。 共有三种推导&#xff…

二十三种设计模式全面解析-当你的对象需要知道其他对象的状态变化时,观察者模式是你的救星!

在软件设计的世界中&#xff0c;有一种设计模式以其简洁而强大的特性闪耀着光芒&#xff0c;它就是——观察者模式&#xff08;Observer Pattern&#xff09;。这个模式它定义了一种一对多的依赖关系&#xff0c;让多个观察者对象同时监听某一个主题对象&#xff0c;为我们创造…

【spring】ApplicationContext的实现

目录 一、ClassPathXmlApplicationContext1.1 说明1.2 代码示例1.3 截图示例 二、FileSystemXmlApplicationContext2.1 说明2.2 代码示例2.3 加载xml的bean定义示例 三、AnnotationConfigApplicationContext3.1 说明3.2 代码示例3.3 截图示例 四、AnnotationConfigServletWebSe…

Git安装与常用命令

Git简介&#xff1a; Git是一个开源的分布式版本控制系统&#xff0c;用于敏捷高效地处理任何或大或小的项目。Git是Linus Torvalds为了帮助管理Linux内核开发而开发的一个开放源代码的版本控制软件。Git与常用的版本控制工具CVS、Subversion等不同&#xff0c;它采用了分布式…

CF1899 G. Unusual Entertainment [二维数点/二维偏序]

传送门:CF [前题提要]:没什么好说的,区域赛爆炸之后发愤加训思维题.秒了div3 A~F的脑筋急转弯,然后被G卡了,树剖dfs序的想法已经想到了,题目也已经化简为两个线段是否存在一个合法位置了.但是MD不会二维数点,用一个树剖扫描线搞来搞去最后还是Tle.果然如下图所说:科技还是十分…

Netty传输object并解决粘包拆包问题

⭐️ 前言 大家好&#xff0c;笔者之前写过一篇文章&#xff0c;《Netty中粘包拆包问题解决探讨》&#xff0c;就Netty粘包拆包问题及其解决方案进行了探讨&#xff0c;本文算是这篇博客的延续。探讨netty传输object的问题。 本文将netty结合java序列化来传输object并解决粘包…

3dMax2024新功能和工作流增强功能速览

3dMax2024新功能和工作流增强功能速览 Autodesk发布的3dMax2024引入了一系列新功能和工作流增强功能&#xff0c;如下所示&#xff1a; 更新的“指定控制器”卷展栏&#xff1a;这个现代化的功能为动画师提供了更高效的工作方式&#xff0c;简化了他们的动画流程。 布尔修饰符…

【DevOps】Git 图文详解(三):常用的 Git GUI

Git 图文详解&#xff08;三&#xff09;&#xff1a;常用的 Git GUI 1.SourceTree2.TortoiseGit3.VSCode 中的 Git 如果不想用命令行工具&#xff0c;完全可以安装一个 Git 的 GUI 工具&#xff0c;用的更简单、更舒服。不用记那么多命令了&#xff0c;极易上手&#xff0c;不…

二、ST-Link驱动的安装

1、灵动mm32单片机 (1)上海灵动微电子股份有限公司 (2)mm32单片机支持ST-Link下载程序。 2、ST-Link驱动的安装 (1)下载地址 ST-Link 官网下载地址 (2)点击获取软件下载ST-Link驱动。(需要登陆ST官网账户) (3)下载后解压&#xff0c;根据电脑位数安装 .exe 文件即可。 6…

若依前后端分离版,快速上手

哈喽~大家好&#xff0c;这篇来看看若依前后端分离版&#xff0c;快速上手&#xff08;肝了挺久的&#xff09;。 &#x1f947;个人主页&#xff1a;个人主页​​​​​ &#x1f948; 系列专栏&#xff1a;【Springboot和Vue全栈开发】…

Javaweb之Vue指令案例的详细解析

2.3.5 案例 需求&#xff1a; 如上图所示&#xff0c;我们提供好了数据模型&#xff0c;users是数组集合&#xff0c;提供了多个用户信息。然后我们需要将数据以表格的形式&#xff0c;展示到页面上&#xff0c;其中&#xff0c;性别需要转换成中文男女&#xff0c;等级需要…

QTableWidget——表格的合并与拆分

一、整体思路 表格的操作使用QTableView::setSpan可以实现表格的行和列的合并 表格拆分没有对应的处理函数 主要思路&#xff1a;对表格的属性、内容、拆分与合并的参数进行存储&#xff0c;在进行拆分时对表格内容进行重新创建&#xff08;不考虑效率问题&#xff09; 二、效…

MyBatis使用注解操作及XML操作

文章目录 1. 注解操作1.1 打印日志1.2 参数传递1.3 增&#xff08;Insert&#xff09;注意1&#xff1a;重命名注意2&#xff1a;返回主键 1.4 删&#xff08;Delete&#xff09;1.5 改&#xff08;Update&#xff09;1.6 查&#xff08;Select&#xff09;1. 配置&#xff0c;…

Windows10下Tomcat8.5安装教程

文章目录 1.首先查看是否安装JDK。2.下载3.解压到指定目录&#xff08;安装路径&#xff09;4.启动Tomcat5.常见问题5.1.如果出现报错或者一闪而过5.2.Tomcat乱码 1.首先查看是否安装JDK。 CMD窗口输入命令 java -version 2.下载 历史版本下载地址&#xff1a;https://archi…

量化交易:传统小市值策略 VS AI市值策略

在BigQuant平台上可以快速开发股票传统策略和股票AI策略&#xff0c;今天拿市值因子来练手&#xff0c;看看两个策略在2015-01-01到2016-12-31这两年时间各自的收益风险情形。 市值因子是国内股票市场能够带来超额收益的alpha因子&#xff0c;已经被验证为长期有效的因子&…

向pycdc项目提的一个pr

向pycdc项目提的一个pr 前言 pycdc这个项目&#xff0c;我之前一直有在关注&#xff0c;之前使用他反编译python3.10项目&#xff0c;之前使用的 uncompyle6无法反编译pyhton3.10生成的pyc文件&#xff0c;但是pycdc可以&#xff0c;但是反编译效果感觉不如uncompyle6。但是版…