variant、optional 和 any

variant、optional和any 这三个模板类是用来取代C风格的一些不安全的代码

optional —— 持有T或为空
variant<T,U> —— 持有T或U(类似于union)
any —— 持有任意类型(类似于void*)

1
2
3
4
5
6
std::optional<int> var1 = 7; 
std::variant<int,string> var2 = 7;
std::any var3 = 7;
auto x1 = *var1 ; // 对 optional 解引用
auto x2 = std::get<int>(var2); // 像访问 tuple 一样访问 variant
auto x3 = std::any_cast<int>(var3); // 转换 any

variant

std::variant 表示一个类型安全的联合体(变化体)std::variant 的一个实例在任意时刻要么保有它的一个可选类型之一的值,要么在错误情况下无值

1
2
3
4
5
6
7
// C风格
union variant{
int,
char
}
// C++风格
typedef std::variant<int,char> variant;

visit

以一或多个 variant 所保有的各实参调用所提供的函数对象

示例

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
#include <cstdio>
#include <type_traits>
#include <variant>
int main() {
// 创建一个 std::variant 变量,可以存放 int 或 char 类型的值,并初始化为整数 1022。
std::variant<int, char> variant = 1022;
// 使用 std::visit 访问 variant 中的值,根据存储的类型输出不同的消息。
std::visit(
[](auto &&arg) {
if (std::is_same_v<std::decay_t<decltype(arg)>, int>) {
printf("variant中存放的是int类型"); // 如果存放的是int类型,输出此消息。
} else if (std::is_same_v<std::decay_t<decltype(arg)>, char>) {
printf("variant中存放的是char类型"); // 如果存放的是char类型,输出此消息。
}
},
variant);
// 将 variant 的值更改为字符 'A'。
variant = 'A';
// 再次使用 std::visit 访问 variant 中的值,根据存储的类型输出不同的消息。
std::visit(
[](auto &&arg) {
if (std::is_same_v<std::decay_t<decltype(arg)>, int>) {
printf("variant中存放的是int类型"); // 如果存放的是int类型,输出此消息。
} else if (std::is_same_v<std::decay_t<decltype(arg)>, char>) {
printf("variant中存放的是char类型"); // 如果存放的是char类型,输出此消息。
}
},
variant);
}

这里只是给出部分示例,因为有些我自己还没看明白,所以后面会更新的

holds_alternative

检查某个 variant 是否当前持有某个给定类型

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <cstdio>
#include <variant>
int main() {
// 创建一个 std::variant 变量,可以存放 int 或 char 类型的值,并初始化为整数 1022。
std::variant<int, char> variant = 1022;
// 检查 variant 中是否存放的是 int 类型的值。
if (std::holds_alternative<int>(variant)) {
// 如果存放的是 int 类型的值,使用 std::get<int> 获取它,并以整数格式输出。
printf("%d\n", std::get<int>(variant));
} else if (std::holds_alternative<char>(variant)) {
// 如果存放的是 char 类型的值,使用 std::get<char> 获取它,并以字符格式输出。
printf("%c\n", std::get<char>(variant));
}
// 将 variant 的值更改为字符 'A'。
variant = 'A';
// 检查 variant 中是否存放的是 int 类型的值。
if (std::holds_alternative<int>(variant)) {
// 如果存放的是 int 类型的值,使用 std::get<int> 获取它,并以整数格式输出。
printf("%d\n", std::get<int>(variant));
} else if (std::holds_alternative<char>(variant)) {
// 如果存放的是 char 类型的值,使用 std::get<char> 获取它,并以字符格式输出。
printf("%c\n", std::get<char>(variant));
}
}

std::get(std::variant)

以给定索引或类型(如果类型唯一)读取 variant 的值,错误时抛出异常

示例

1
2
3
4
5
6
7
8
#include <cstdio>
#include <variant>
int main() {
// 创建一个 std::variant 变量,可以存放 int 或 char 类型的值,并初始化为整数 1022。
std::variant<int, char> variant = 1022;
// 使用get函数获取值并输出
printf("%d\n", std::get<int>(variant));
}

optional

std::optional 管理一个可选的容纳值,既可以存在也可以不存在的值

1
2
3
4
// C风格
int optional = NULL;
// C++风格
std::optional<int> optional = std::nullopt;

has_value

检查对象是否含值

示例

1
2
3
4
5
6
7
8
9
#include <cstdio>
#include <optional>
int main() {
std::optional<int> optional = std::nullopt;
if (!optional.has_value()) {
// 如果optional为空就输出
printf("optional为空");
}
}

any

std::any 描述用于任何可拷贝构造类型的单个值的类型安全容器

1
2
3
4
5
// C风格
int value = 10;
void *any = &value;
// C++风格
std::any any = 10;

has_value

检查对象是否含有值

示例

1
2
3
4
5
6
7
8
9
#include <any>
#include <cstdio>
int main() {
std::any any = 10;
if (any.has_value()) {
// 如果any不为空就输出
printf("any不为空\n");
}
}

type

返回所含值的 typeid

示例

1
2
3
4
5
6
7
8
9
#include <any>
#include <cstdio>
int main() {
std::any any = 10;
if (any.type() == typeid(int)) {
// any中存放的是int则输出
printf("any中存放的是int类型\n");
}
}

any_cast

对被容纳对象的类型安全访问

示例

1
2
3
4
5
6
7
8
9
#include <any>
#include <cstdio>
int main() {
std::any any = 10;
if (any.type() == typeid(int)) {
// any中存放的是int则输出
printf("any中存放的是%d\n",std::any_cast<int>(any));
}
}

目前variant、optional和any的使用也就这么点,后续我还会补充一些我遗漏的内容