# std::variant用法
# Union类型
与union类型作对比,union类型是为了在同块内存中支持多种类型数据的场景,譬如一块内存既可能放char又可能放int,那就可以定义成Union类型:
#include <cstdio>
int main(void) {
union U1
{
int a;
char b;
double c;
};
U1 u1;
u1.a = 1000;
printf("u1 %d u1.b %d\n", u1.a, *reinterpret_cast<int*>(&(u1.b)));
printf("u1 %x u1.a %x u1.b %x u1.c %x\n",
&u1, &(u1.a), &(u1.b), &(u1.c));
return 0;
}
// u1 1000 u1.b 1000
// u1 302f1bf0 u1.a 302f1bf0 u1.b 302f1bf0 u1.c 302f1bf0
可以看到u1, u1.a,u1.b,u1.c都指向相同的地址,即Union类型的首地址.
# C++17中引入的variant类型
variant
属于 C++ 标准库中的 std::variant
是一个类型安全的联合体,可以存储固定集合中的任意类型的值。这使得 std::variant
成为处理那些可能需要存储不同类型数据的情况的理想选择。
特点:
1.类型安全: 与传统的 C 联合体(
union
)不同,std::variant
在类型安全方面提供了显著的改进。它能保证在任何时候都只包含其能持有的类型之一,并且提供了丰富的接口来检查和访问存储的数据。2.自动管理:
std::variant
自动处理类型的构造、析构和赋值,确保资源的正确管理。3.访问控制: 提供了安全的方式访问存储的数据,例如
std::get
、std::visit
等函数。
访问元素
std::get
:可以通过 std::get<Type>(variant)
获取 variant
中存储的类型为 Type 的值。如果 variant 当前不持有该类型,则会抛出 std::bad_variant_access
异常。
std::visit
应用一个访问者(通常是一个 lambda 表达式或函数对象)到 variant 中存储的值上
std::holds_alternative
使用std::holds_alternative<T>(v)
函数,这个函数返回一个布尔值,表示std::variant
是否当前持有类型T
.
std::get_if
提供了一种安全的方式来尝试获取std::variant
中存储的值,而不会抛出异常。它返回指向存储的值的指针,如果std::variant
当前不持有请求的类型,则返回nullptr
。
#if defined(__cplusplus)
#if __cplusplus == 201703L
#include <variant>
#include <string>
#include <iostream>
void VariantTest() {
// 定义一个可以存储 int 或 double 或 std::string 的 variant
std::variant<int, double, std::string> v;
v = 10;
printf("int: %d\n", std::get<int>(v));
v = 12.3;
printf("double: %f\n", std::get<double>(v));
v = "string";
printf("string: %s\n", std::get<std::string>(v).c_str());
try {
printf("int: %d\n", std::get<int>(v)); // 这将抛出异常,因为当前存储的是 string
} catch (const std::bad_variant_access&) {
printf("Error: The current variant does not hold an int.\n");
}
std::visit([](auto && arg) {
std::cout << "arg: " << arg << std::endl;
}, v);
if (std::holds_alternative<std::string>(v)) {
std::cout << "Variant holds a string." << std::endl;
} else {
std::cout << "Variant does not hold a string." << std::endl;
}
if (auto val = std::get_if<int>(&v)) {
std::cout << "The value is: " << *val << std::endl;
} else {
std::cout << "Variant does not hold an int." << std::endl;
}
printf("sizeof v: %lu\n", sizeof(v));
// int: 10
// double: 12.300000
// string: string
// Error: The current variant does not hold an int.
// arg: string
// Variant holds a string.
// Variant does not hold an int.
// sizeof v: 40
}