September 30, 2023

variant、optional 和 any

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

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

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
的一个实例在任意时刻要么保有它的一个可选类型之一的值,要么在错误情况下无值

// C风格
union variant{
    int,
    char
}
// C++风格
typedef std::variant<int,char> variant;

visit

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

示例

#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 是否当前持有某个给定类型

示例

#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 的值,错误时抛出异常

示例

#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 管理一个可选的容纳值,既可以存在也可以不存在的值

// C风格
int optional = NULL;
// C++风格
std::optional<int> optional = std::nullopt;

has_value

检查对象是否含值

示例

#include <cstdio>
#include <optional>
int main() {
    std::optional<int> optional = std::nullopt;
    if (!optional.has_value()) {
        // 如果optional为空就输出
        printf("optional为空");
    }
}

any

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

// C风格
int value = 10;
void *any = &value;
// C++风格
std::any any = 10;

has_value

检查对象是否含有值

示例

#include <any>
#include <cstdio>
int main() {
    std::any any = 10;
    if (any.has_value()) {
        // 如果any不为空就输出
        printf("any不为空\n");
    }
}

type

返回所含值的 typeid

示例

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

any_cast

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

示例

#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的使用也就这么点,后续我还会补充一些我遗漏的内容

About this Post

This post is written by JinHong Zeng, licensed under CC BY-NC 4.0.

#CPP