说明

类模板 std::variant表示一个类型安全的联合体。 std::variant 的一个实例在任意时刻要么保有其一个可选类型之一的值,要么在错误情况下无值(此状态难以达成,见 valueless_by_exception )。
与联合体在聚合初始化中的行为一致, 若 variant 保有某个对象类型T的值,则直接于 variant的对象表示中分配 T 的对象表示。不允许 variant分配额外的(动态)内存。
variant 不容许保有引用、数组,或类型 void 。空 variant亦为病式(可用 std::variant<std::monostate> 代替)。
variant 容许保有同一类型多于一次,而且可保有同一类型的不同 cv 限定版本。
同联合体,默认构造的 variant保有其首个选项的值,除非该选项不是可默认构造的(该情况下 variant亦非可默认构造:能用辅助类 std::monostate 使这种 variant 可默认构造)。
模板形参
Types - 可存储于此 variant 中的类型。所有类型必须满足可析构 (Destructible) 要求(特别是不允许数组类型和非对象类型)。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102

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

/*
类模板 std::variant 表示一个类型安全的联合体。 std::variant 的一个实例在任意时刻要么保有其一个可选类型之一的值,要么在错误情况下无值(此状态难以达成,见 valueless_by_exception )。
与联合体在聚合初始化中的行为一致, 若 variant 保有某个对象类型 T 的值,则直接于 variant 的对象表示中分配 T 的对象表示。不允许 variant 分配额外的(动态)内存。
variant 不容许保有引用、数组,或类型 void 。空 variant 亦为病式(可用 std::variant<std::monostate> 代替)。
variant 容许保有同一类型多于一次,而且可保有同一类型的不同 cv 限定版本。
同联合体,默认构造的 variant 保有其首个选项的值,除非该选项不是可默认构造的(该情况下 variant 亦非可默认构造:能用辅助类 std::monostate 使这种 variant 可默认构造)。
模板形参
Types - 可存储于此 variant 中的类型。所有类型必须满足可析构 (Destructible) 要求(特别是不允许数组类型和非对象类型)。
*/

int main()
{
std::variant<int, float> v, w;
v = 12; // v 含 int
int 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 与 1
try {
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"; // 转换赋值在无歧义时亦起作用
if (std::holds_alternative<std::string>(x))
{
std::cout << "x std::string:" << std::get<std::string>(x) << "\n";
}
std::variant<std::string, void const*> y("abc");
// 传递 char const * 时转换成 void const *
y = "xyz"s;
if (std::holds_alternative<std::string>(y))
{
std::cout << "y std::string:" << std::get<std::string>(y) << "\n";
}
if (std::holds_alternative<void const*>(y))
{
std::cout << "y char const *:" << (char const *)std::get<void const*>(y) << "\n";
}
// test
std::variant<int, float, std::string, void const*> test;
test = 1;
test = "abc";
// test = std::string("efg");
if (std::holds_alternative<std::string>(test))
{
std::cout << "string:" << std::get<std::string>(test) << "\n";
}
if (std::holds_alternative<int>(test))
{
std::cout << "int:" << std::get<int>(test) << "\n";
}
if (std::holds_alternative<void const*>(test))
{
std::cout << "char*:" << (char const*)std::get<void const*>(test) << "\n";
}
test = 1;
test = "abc";
test = std::string("efg");
if (std::holds_alternative<std::string>(test))
{
std::cout << "string:" << std::get<std::string>(test) << "\n";
}
if (std::holds_alternative<int>(test))
{
std::cout << "int:" << std::get<int>(test) << "\n";
}
if (std::holds_alternative<void const*>(test))
{
std::cout << "char*:" << (char const*)std::get<void const*>(test) << "\n";
}
test = std::string("efg");
test = "abc";
test = 1;
if (std::holds_alternative<std::string>(test))
{
std::cout << "string:" << std::get<std::string>(test) << "\n";
}
if (std::holds_alternative<int>(test))
{
std::cout << "int:" << std::get<int>(test) << "\n";
}
if (std::holds_alternative<void const*>(test))
{
std::cout << "char*:" << std::get<void const*>(test) << "\n";
}
return 0;
}

输出

1
2
3
4
5
x std::string:def
y std::string:xyz
char*:abc
string:efg
int:1

参考

https://zh.cppreference.com/w/cpp/utility/variant