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

编程入门 行业动态 更新时间:2024-10-28 19:31:01

(C++17) <a href=https://www.elefans.com/category/jswz/34/1711810.html style=variant的使用与union对比"/>

(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

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

更多推荐

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

本文发布于:2023-11-15 15:58:09,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1602377.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:variant   union

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!