std::variant 是 C++17 标准引入的一种 union,std::variant 可以在一个变量中存储不同类型的数据,并保持类型安全,这是传统的 union 所不能提供的。
主要特点#
类型安全#
使用 std::variant 可以保证任何时候都能确保访问正确的类型值,如果访问错误的类型会抛出 std::bad_variant_access 异常。
自动管理#
std::variant 和 std::any 可以管理内部数据的创建和销毁,保证正确的资源管理。
访问控制#
可以通过 std::get 访问 std::variant 中的数据(需要确保类型正确)
可以和 visit 结合使用#
可以使用 std::visit 对存储在 std::variant 中的数据进行操作。
示例#
#include <variant>
#include <iostream>
#include <string>
int main() {
std::variant<int, float, std::string> v;
v = 20;
std::cout << std::get<int>(v) << std::endl; // 输出 20
v = 3.14f;
std::cout << std::get<float>(v) << std::endl; // 输出 3.14
v = "Hello, world";
std::cout << std::get<std::string>(v) << std::endl; // 输出 Hello, world
// 安全访问
try {
std::cout << std::get<float>(v) << std::endl; // 尝试获取float,但当前是std::string,将抛出异常
} catch (const std::bad_variant_access& e) {
std::cout << e.what() << std::endl; // 输出异常信息
}
// 使用 visit
std::visit([](auto&& arg) {
std::cout << arg << std::endl;
}, v); // 安全地打印当前存储的值,这里是 "Hello, world"
return 0;
}
在这个示例中,std::variant 被用来存储一个 int,一个 float,和一个 std::string。可以看到如何安全地使用 std::get 来访问 std::variant 中的数据,并且如何使用 std::visit 来应用函数或者访问者到存储的值上。
实际环境#
inline ResourceVariant ResourceManager::flipResource(ResourceVariant resource)
{
return std::visit([](auto&& res) -> ResourceVariant {
using T = std::decay_t<decltype(res)>;
if constexpr (std::is_same_v<T, IMAGE>) {
IMAGE flippedImg;
flipImage(&res, &flippedImg);
return flippedImg;
}
else if constexpr (std::is_same_v<T, Atlas>) {
Atlas flippedAtla;
flipAtlas(res, flippedAtla);
return flippedAtla;
}
}, resource);
}
这段代码展示了如何使用 std::variant 和 std::visit 来处理不同类型的资源。这里,ResourceManager::flipResource 方法接受一个名为 resource 的 ResourceVariant 类型的参数,并返回一个同样类型的 ResourceVariant。这个 ResourceVariant 是一个 std::variant 类型,可以包含不同的资源类型(比如 IMAGE 或 Atlas)