(C++17) variant的使用与union对比

文章目录

  • 前言与需求
  • union
    • 内存映射图
    • C++11的union
  • 使用
    • ref示例
    • 构造
      • 普通构造
      • 置空
      • emplace
      • monostate
    • 访问
      • std::get<>
      • std::holds_alternative<>
      • 获取指针std::get_if<>
      • 获取可选数量个数std::variant_size
  • END

前言与需求

联合体,是在C语言时代就存在的概念。主要应用在一些收内存限制较大的情景。

但是传统C的限制太大,但是到了C++中给出了更安全的类型std::variant

union

内存映射图

先来看一张C语言数据结构内存映射图

!网图(非原创),侵删!

在这里插入图片描述

在union中所有字段是公用一块内存区域的。

C++11的union

在旧时union中成员不能是一个非凡类型。到了C++11解除了限制,只要是非应用类型即可。

其实union也可以单独开一篇文章来讲,这里给个简单示例,不做过多讲解:

#include <iostream>
#include <string>
#include <vector>union U {U() {}~U() {}static int s;int   x;float y;std::string      str;std::vector<int> vec;
};
// 同类的静态成员类似
int U::s = 10;int main() {std::cout << U::s << std::endl;U u;// 使用 placement new 和 手动析构new (&u.str) std::string("hello world");std::cout << u.str << std::endl;u.str.~basic_string();new (&u.vec) std::vector<int>(2, -1);u.vec.push_back(1);for (int i = 0; i < u.vec.size(); i += 1) {std::cout << u.vec[i] << std::endl;}u.vec.~vector();return 0;
}

使用

std::variant - cppreference.com

ref示例

std::variant 是类型安全的,只能访问一种类型

#include <cassert>
#include <string>
#include <variant>int main() {std::variant<int, float> v, w;v     = 12;  // v 含 intint i = std::get<int>(v);w     = std::get<int>(v);w     = std::get<0>(v);  // 与前一行效果相同w     = v;               // 与前一行效果相同//  std::get<double>(v); // 错误: [int, float] 中无 double//  std::get<3>(v);      // 错误:合法下标值为 0 与 1try {std::get<float>(w);  // w 含 int 而非 float :将抛出} catch (const std::bad_variant_access&) {}using namespace std::literals;std::variant<std::string> x("abc");  // 转换构造函数在无歧义时起作用x = "def";  // 转换赋值在无歧义时亦起作用std::variant<std::string, void const*> y("abc");// 传递 char const * 时转换成 void const *assert(std::holds_alternative<void const*>(y));  // 成功y = "xyz"s;assert(std::holds_alternative<std::string>(y));  // 成功
}

构造

直接赋值即可。

普通构造

#include <iostream>
#include <string>
#include <variant>void fun() {// 可以相同std::variant<int, int> var;// 操作比较特殊
}int main() {std::variant<std::string, int> empty;std::variant<std::string, int> var("abc");std::cout << std::get<0>(var) << std::endl;var = 123;std::cout << std::get<1>(var) << std::endl;std::get<1>(var) = 654321;std::cout << std::get<1>(var) << std::endl;
}

置空

#include <iostream>
#include <string>
#include <variant>int main() {std::variant<int, std::string> v = "abc";// v.index = 1std::cout << "v.index = " << v.index() << '\n';// 置空了v = {};// v.index = 0std::cout << "v.index = " << v.index() << '\n';
}

emplace

可以原地构造

#include <iostream>
#include <string>
#include <variant>int main() {std::variant<std::string> var;var.emplace<0>(2, 'a');std::cout << std::get<0>(var) << std::endl;var.emplace<std::string>("Hello World");std::cout << std::get<std::string>(var) << std::endl;
}

monostate

有一类情况比较特殊。

有意为行为良好的 std::variant 中空可选项所用的单位类型。具体而言,非可默认构造的 variant 可以列 std::monostate 为其首个可选项:这使得 variant 自身可默认构造。

  • std::monostate
  • valueless_by_exception()
#include <iostream>
#include <variant>struct S {int value;S(int i) : value(i) {std::cout << __func__ << std::endl;}
};int main() {// 若无 monostate 类型则此声明将失败。// 这是因为 S 不可默认构造。std::variant<std::monostate, S> var;// 不保有值std::cout << std::boolalpha << var.valueless_by_exception() << std::endl;// std::get<S> 将抛异常!我等需要赋一个值// var.index() 现为 0 ——首个元素std::cout << "cur index = " << var.index() << '\n';var = 12;std::cout << std::get<S>(var).value << '\n';
}

访问

std::get<>

请注意同类型的情况

#include <iostream>
#include <string>
#include <variant>void fun0() {// 可以相同std::variant<int, int> var;// 编译不通过,非动态错误// var = 10;// 编译不通过,非动态错误// std::get<int>(var) = 100;// 下标访问可行std::get<0>(var) = 10;try {std::cout << std::get<1>(var) << std::endl;} catch (const std::bad_variant_access& e) {// std::get: wrong index for variantstd::cout << e.what() << std::endl;}
}void fun1() {std::variant<std::string, int> var("abc");std::cout << std::get<0>(var) << std::endl;std::cout << std::get<std::string>(var) << std::endl;
}int main() {fun0();fun1();
}

std::holds_alternative<>

判断是否可以转换

#include <iostream>
#include <string>
#include <variant>int main() {std::cout << std::boolalpha;std::variant<std::string, int> var("abc");std::cout << "int " << std::holds_alternative<int>(var) << std::endl;std::cout << "string " << std::holds_alternative<std::string>(var)<< std::endl;
}

获取指针std::get_if<>

#include <iostream>
#include <variant>int main() {std::variant<int, float> var;std::cout << &var << std::endl;// 整形var       = 12;auto pval = std::get_if<int>(&var);std::cout << pval << std::endl;if (pval) {std::cout << "variant value: " << *pval << '\n';} else {std::cout << "failed to get value!" << '\n';}// 浮点数var        = 12.3f;auto pval2 = std::get_if<float>(&var);std::cout << pval2 << std::endl;if (pval2) {std::cout << "variant value: " << *pval2 << '\n';} else {std::cout << "failed to get value!" << '\n';}
}
0xc10cbffba0
0xc10cbffba0
variant value: 12
0xc10cbffba0
variant value: 12.3

获取可选数量个数std::variant_size

在编译器确定

  • std::variant_size
  • std::variant_size_v
#include <any>
#include <cstdio>
#include <variant>// 全部 passstatic_assert(std::variant_size_v<std::variant<>> == 0);
static_assert(std::variant_size_v<std::variant<int>> == 1);
static_assert(std::variant_size_v<std::variant<int, int>> == 2);
static_assert(std::variant_size_v<std::variant<int, int, int>> == 3);
static_assert(std::variant_size_v<std::variant<int, float, double>> == 3);
// std::monostate 也算一个占位
static_assert(std::variant_size_v<std::variant<std::monostate, void>> == 2);
static_assert(std::variant_size_v<std::variant<const int, const float>> == 2);
static_assert(std::variant_size_v<std::variant<std::variant<std::any>>> == 1);int main() {std::puts("All static assertions passed.");
}



END

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

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

相关文章

Python BeautifulSoup 库使用教程

文章目录 简介安装 BeautifulSoup 库BeautifulSoup 库的导入BeautifulSoup 库依赖的解析库创建 BeautifulSoup 对象CSS选择器1、通过标签名查找2、通过 CSS 的类名查找3、通过 Tag(标签) 的 id 查找4、通过 是否存在某个属性来查找5、通过 某个标签是否存在某个属性来查找 获取…

【微服务专题】手写模拟SpringBoot

目录 前言阅读对象阅读导航前置知识笔记正文一、工程项目准备1.1 新建项目1.1 pom.xml1.2 业务模拟 二、模拟SpringBoot启动&#xff1a;好戏开场2.1 启动配置类2.1.1 shen-base-springboot新增2.1.2 shen-example客户端新增启动类 三、run方法的实现3.1 步骤一&#xff1a;启动…

合并二叉树(Java)

题目描述 给你两棵二叉树&#xff1a; root1 和 root2 。 想象一下&#xff0c;当你将其中一棵覆盖到另一棵之上时&#xff0c;两棵树上的一些节点将会重叠&#xff08;而另一些不会&#xff09;。你需要将这两棵树合并成一棵新二叉树。合并的规则是&#xff1a;如果两个节点重…

耗时3年写了一本数据结构与算法pdf!开源了

前言 大家好&#xff0c;我是bigsai&#xff0c;很早就在写博客&#xff0c;我将csdn的文章整理成了一个pdf&#xff0c;并且开源到github上&#xff01; 自己写东西断断续续也不少时间了&#xff0c;也写了不少东西(虽然是偏向小白)&#xff0c;这个其实花费的时间还是比较多…

JuCheap开发的微信小程序商城(NetCore商城)

一、目的 最近工作需要&#xff0c;在学习微信小程序的开发&#xff0c;用周末空闲时间开发了一个微信小程序商城。 二、功能 2.1 管理后台 管理后台是基于JuCheap开发的&#xff0c;使用Net6Vue3ElementPlus开发&#xff0c;具体功能包含如下&#xff1a; 2.1.1 店铺模块…

BI 数据可视化平台建设(1)—交叉表组件演变实战

作者&#xff1a;vivo 互联网大数据团队 - Zhu Jianchen 本文是vivo互联网大数据团队《BI数据可视化平台建设》系列文章第1篇 - 交叉表组件。 交叉表在数据分析里应用广泛&#xff0c;通过本文&#xff0c;你将了解到&#xff1a; 交叉表的基本概念&#xff0c;以及BI可视化平…

有符号数是如何判断正负符号位的?

文章目录 有符号数是如何判断正负符号位的&#xff1f; 运行结果&#xff1a; 有符号数是如何判断正负符号位的&#xff1f; #include<stdio.h> int main() {int input_data 0;printf("Please input the data ! \n");scanf("%d",&input_data);…

Java必刷入门递归题×5(内附详细递归解析图)

目录 1.求N的阶乘 2.求12...N的和 3.顺序打印数字的每一位 4.求数字的每一位之和 5.求斐波拉契数列 1.求N的阶乘 &#xff08;1&#xff09;解析题目意思 比如求5的阶乘&#xff0c;符号表示就是5&#xff01;&#xff1b;所以5&#xff01;5*4*3*2*1我们下面使用简单的…

Openlayers:自定义Controls

Openlayers是一款优秀的二维开源地图框架,支持矢量/栅格图层,支持移动端,并且易于自定义和拓展。下面来讲述一下自定义Control的基本思路。 openlayers-features 问题描述 最近在做个人项目时,遇到了一个小问题,就是在地图中心添加一个十字针形状的符号,用来表示地图中心…

javaSE学习笔记(五)集合框架-Collection,List,Set,Map,HashMap,Hashtable,ConcurrentHashMap

目录 四、集合框架 1.集合概述 集合的作用 集合和数组的区别 集合继承体系 数组和链表 数组集合 链表集合 2.Collection 方法 集合遍历 并发修改异常 3.List List集合的特有功能&#xff08;核心是索引&#xff09; 集合遍历 并发修改异常产生解决方案ListItera…

文本处理大师:Linux中grep、sed和awk的绝佳教程

1 grep 搜索关键字 全局搜索正则表达式 1.1 基本格式 grep root passwd #过滤含有root关键字-e 多个过滤词 grep -e root -e bash pa grep -E "root|bin" pa # 等同于上面的命令-i 忽略大小写 -E 过滤 grep -E "\<root" passwd ##root字符之前不能有…

Android Studio真机运行时提示“安装失败”

用中兴手机真机运行没问题&#xff0c;用Vivo运行就提示安装失败。前提&#xff0c;手机已经打开了调试模式。 报错 Android Studio报错提示&#xff1a; Error running app The application could not be installed: INSTALL_FAILED_TEST_ONLY 手机报错提示&#xff1a; 修…