c++ std::variant用法

std::variant

Union类型的问题:

  • 无法知道当前使用的类型是什么
  • union无法自动调用底层数据成员的析构函数。联合体无法对其内部的数据属性的生命周期的全面支持,因为当外部代码调用Union时在切换类型,它无法做到对当前使用的对象,并自动调用其析构函数。
  • C/C++没有原生的工具可以检测Union内部当前的活动类型。
  • 不能有non-trivial的成员,比如std::string(从c++ 11起, union原则上可以有non-trivial的成员,但是必须实现特殊的成员函数,比如复制构造函数和析构函数,因为只有通过代码逻辑才能知道哪个成员是可用的。)
  • 不能从union中派生类。

在 C++17 之前,为了改进这些问题,提出了std::variant。

  • 与C语言中传统的 union 类型相同的是,variant 也是联合(union)类型。即 variant 可以存放多种类型的数据,但任何时刻最多只能存放其中一种类型的数据。
  • 与C语言中传统的 union 类型所不同的是,variant 是可辨识的类型安全的联合(union)类型。即 variant 无须借助外力只需要通过查询自身就可辨别实际所存放数据的类型。

std::variant 基础用法

构造函数

std::variant<int, double, std::string> x, y;

x,y是一个可存放 int, double, std::string 这三种类型数据的变体类型的对象

std::in_place_index、std::in_place_type 显式赋值

显式指定当前索引/类型,并使用后续参数进行原地构造

variant<vector<int>, string> v{ std::in_place_index<0>, { 0, 1, 2, 3 } };
variant<vector<int>, string> v{ std::in_place_type<int>, { 0, 1, 2, 3 } };

修改值

赋值和emplace()操作对应于初始化


std::variant<int, int, std::string> var; // sets first int to 0, index()==0
var = "hello"; // sets string, index()==2
var.emplace<1>(42); // sets second int, index()==1

获取当前使用的type 在variant声明中的索引

x = 100.0f;
std::cout << "可变体的活动类型返回的index:" << x.index() << std::endl;

获取std::variant中的值

使用std::get() 或直接std::get()来获取variant中包含的值,std::get(v) 如果变体类型 v 存放的数据类型为 T,那么返回所存放的数据,否则报错

double d = std::get<double>(x);
std::string s = std::get<2>(y);

如果std::variant中当前存储的不是对应Type的值, 则会抛出std::bad_variant_access类型的异常

try
{
    int i = std::get<int>(x);
}
catch (std::bad_variant_access e)
{
    std::cerr << e.what() << std::endl;
}

get_if()

除了会引发异常的std::get<>,也有无异常的 std::get_if() 方法,get_if通常保证std::get在访问可变体时不会抛出bad_variant_access 异常,提供了访问前的类型安全判断。需要自行判断返回的指针类型是否为空。
std::get_if(&v) 如果变体类型 v 存放的数据类型为 T,那么返回所存放数据的指针,否则返回空指针。

int* i = std::get_if<int>(&x);
if (i == nullptr)
{
    std::cout << "wrong type" << std::endl;
}
else
{
    std::cout << "value is " << *i << std::endl;
}

同时具有bool和std::string

如果一个std::variant<>同时有bool和std::string两个备选项,字符串字面量转换为bool比转换为std::string匹配

 #include <iostream>
#include <variant>
 
int main()
{
    std::variant<bool, std::string> v;
    v = "hi"; // OOPS: sets the bool alternative
    std::cout << "index: " << v.index() << '\n';
 
    std::visit([](const auto& val) {std::cout << "value: " << val << '\n'; }, v);
 
    return 0;
}

在这里插入图片描述
字符串常量值被解释为通过Boolean值true初始化变量(true是因为指针不是0)

解决方案

v.emplace<1>("hello"); // explicitly assign to second alternative
v.emplace<std::string>("hello"); // explicitly assign to string alternative
v = std::string{"hello"}; // make sure a string is assigned
 
using namespace std::literals; // make sure a string is assigned
v = "hello"s;

std::holds_alternative(v)

查询变体类型 v 是否存放了 T 类型的数据。

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

using namespace std;

int main()
{
    variant<int, double, string> v; // v == 0
    v = 1;
    bool has_int = holds_alternative<int>(v);
    bool has_double = holds_alternative<double>(v);
    cout << v.index() << has_int << has_double << get<0>(v) << *get_if<0>(&v) << endl; // 01011
    v = 2.0;
    cout << v.index() << (get_if<int>(&v) == nullptr) << get<1>(v) << get<double>(v) << endl; // 1122
    v = "a";
    cout << v.index() << get<2>(v) << get<string>(v) << endl; // 2aa
}

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

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

相关文章

Java(五)(Object类,克隆,Objects类,包装类,StringBuilder,StringJoiner,BigDecimal)

目录 Object类 Object类的常见方法: 克隆 浅克隆 深克隆 Objects类 包装类 StringBuilder StringJoiner BigDecimal Object类 Object类是java中的祖宗类,因此,Java中所有的类的对象都可以直接使用object类提供的一些方法 Object类的常见方法: public String toStrin…

【黑马甄选离线数仓day01_项目介绍与环境准备】

1. 行业背景 1.1 电商发展历史 电商1.0: 初创阶段20世纪90年代&#xff0c;电商行业刚刚兴起&#xff0c;主要以B2C模式为主&#xff0c;如亚马逊、eBay等 ​ 电商2.0: 发展阶段21世纪初&#xff0c;电商行业进入了快速发展阶段&#xff0c;出现了淘宝、京东等大型电商平台&a…

Halcon Solution Guide I basics(3): Region Of Interest(有兴趣区域/找重点)

文章目录 文章专栏前言文章解读前言创建ROI案例1&#xff1a;直接截取ROI手动截取ROI 总结ROI套路获取窗口句柄截取ROI区域获取有效区域 Stop组合 文章专栏 Halcon开发 Halcon学习 练习项目gitee仓库 CSDN Major 博主Halcon文章推荐 前言 今天来看第三章内容&#xff0c;既然是…

忘记7-zip密码,如何解压文件?

7z压缩包设置了密码&#xff0c;解压的时候就需要输入正确对密码才能顺利解压出文件&#xff0c;正常当我们解压文件或者删除密码的时候&#xff0c;虽然方法多&#xff0c;但是都需要输入正确的密码才能完成。忘记密码就无法进行操作。 那么&#xff0c;忘记了7z压缩包的密码…

代码规范之-理解ESLint、Prettier、EditorConfig

前言 团队多人协同开发项目&#xff0c;困扰团队管理的一个很大的问题就是&#xff1a;无可避免地会出现每个开发者编码习惯不同、代码风格迥异&#xff0c;为了代码高可用、可维护性&#xff0c;需要从项目管理上尽量统一和规范代码。理想的方式需要在项目工程化方面&#xff…

力扣:175. 组合两个表(Python3)

题目&#xff1a; 表: Person ---------------------- | 列名 | 类型 | ---------------------- | PersonId | int | | FirstName | varchar | | LastName | varchar | ---------------------- personId 是该表的主键&#xff08;具有唯一值的列&#…

设计循环队列,解决假溢出问题

什么是假溢出&#xff1f; 当我们使用队列这种基本的数据结构时&#xff0c;很容易发现&#xff0c;随着入队和出队操作的不断进行&#xff0c;队列的数据区域不断地偏向队尾方向移动。当我们的队尾指针指向了队列之外的区域时&#xff0c;我们就不能再进行入队操作了&#xff…

【shell】循环语句(for、while、until)

目录 一、循环语句的特点 二、三种常用的循环 2.1 for循环 2.2 while循环 2.3 until循环 2.4 死循环 2.5 关于continue和break以及exit 三、实操案例 3.1 累加1到100&#xff08;5种办法&#xff0c;穿插多种运算习惯&#xff09; 3.2 批量修改文件名称 3.3 pi…

yapi==使用依赖包里的类作为入参/返回值导出后没有备注

比如模块A中有个MyDemoEntity类,在B中以依赖的形式引入了A,并在B的接口中以MyDemoEntity作为返回值,导出到YAPI发现MyDemoEntity的备注没了。 解决: 将A的内容安装到本地MAVEN仓库,并且需要将源码也一起安装 <build><resources><resource><director…

记录--手写一个 v-tooltip 指令

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 前言 日常开发中&#xff0c;我们经常遇到过tooltip这种需求。文字溢出、产品文案、描述说明等等&#xff0c;每次都需要写一大串代码&#xff0c;那么有没有一种简单的方式呢&#xff0c;这回我们用指…

第一百七十六回 如何创建渐变色边角

文章目录 1. 概念介绍2. 实现方法3. 代码与细节3.1 示例代码3.2 代码细节 4. 内容总结 我们在上一章回中介绍了"如何创建放射形状渐变背景"相关的内容&#xff0c;本章回中将介绍"如何创建渐变色边角".闲话休提&#xff0c;让我们一起Talk Flutter吧。 1.…

Axios使用方式

ajax是JQUERY封装的XMLHttprequest用来发送http请求 Axios简单点说它就是一个js库,支持ajax请求,发送axios请求功能更加丰富,丰富在哪不知道 1.npm使用方式 vue项目中 npm install axios 2.cdn方式 <script src"https://unpkg.com/axios/dist/axios.min.js">…

行情分析——加密货币市场大盘走势(11.22)

大饼昨日晚上打了止损&#xff0c;笔者入场了空单&#xff0c;目前来看上涨乏力&#xff0c;下跌是必然的&#xff0c;昨日的下跌跌破了蓝色上涨趋势线&#xff0c;而今日白天开始反弹&#xff0c;别着急抄底&#xff0c;下跌还没有结束。 空单策略&#xff1a;入场36500 止盈…

为UE和Unity开发者准备的Godot指南

为UE和Unity开发者准备的Godot指南 ——两位大哥打架&#xff0c;请带上我 这两天游戏行业又开始热闹了&#xff0c;昨天两条信息直接刷爆朋友圈&#xff0c;最大的两家游戏引擎公司怼起来了。 《为Unity开发者准备的虚幻引擎指南》&#xff1a; 为Unity开发者准备的虚幻引擎指…

Autocad2020切换经典界面

Autocad2020切换经典界面 1.更改1.1设置另存为 1.更改 1.1设置另存为

SQL语句执行过程

一条 SQL 的执行过程可以大致分为以下几个步骤&#xff1a; 连接器&#xff1a; ○ 客户端与数据库建立连接&#xff0c;并发送 SQL 语句给数据库服务。 ○ 连接器验证客户端的身份和权限&#xff0c;确保用户有足够的权限执行该 SQL 语句。查询缓存&#xff1a; ○ 连接器首先…

Redis面试内容,Redis过期策略,Redis持久化方式,缓存穿透、缓存击穿和缓存雪崩,以及解决办法

文章目录 一、redis什么是RedisRedis使用场景1、缓存2、数据共享[分布式](https://so.csdn.net/so/search?q分布式&spm1001.2101.3001.7020)3、分布式锁4、全局ID5、计数器6、限流7、位统计 Redis有5中数据类型&#xff1a; SSHLZRedis中一个key的值每天12点过期&#xff…

编码的发展历史

编码的发展历史 ASCII&#xff1a; ASCII编码使用7位二进制数表示一个字符&#xff0c;范围从0到127。每个字符都有一个唯一的ASCII码值与之对应。例如&#xff0c;大写字母"A"的ASCII码是65&#xff0c;小写字母"a"的ASCII码是97。 ASCII字符集包括英文…

【python基础】python可变序列与不可变序列

文章目录 前言一、序列类型定义二、对序列类型的切片操作三、使用 与 * 对序进行操作四、增量赋值 和 * 前言 本文主要讲可变序列与不可变序列一些简单的应用。 一、序列类型定义 按序列能否被修改分为&#xff1a;可变序列与不可变序列。 可变序列&#xff1a;可以进行增、…

短期风速预测|LSTM|ELM|批处理(matlab代码)

1主要内容 该程序是预测类的基础性代码&#xff0c;程序对河北某地区的气象数据进行详细统计&#xff0c;程序最终得到pm2.5的预测结果&#xff0c;通过更改数据很容易得到风速预测结果。程序主要分为三部分&#xff0c;分别是基于LSTM算法、基于ELM算法和基于LSTM和批处理组合…