std::variant is a union introduced in the C++17 standard that can store different types of data in a single variable while maintaining type safety, something traditional unions cannot provide.
Main Features#
Type Safety#
Using std::variant ensures that the correct type value is accessed at all times; accessing the wrong type will throw a std::bad_variant_access exception.
Automatic Management#
std::variant and std::any can manage the creation and destruction of internal data, ensuring proper resource management.
Access Control#
Data in std::variant can be accessed through std::get (ensuring the type is correct).
Can be Used with Visit#
std::visit can be used to operate on data stored in std::variant.
Example#
#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; // Outputs 20
v = 3.14f;
std::cout << std::get<float>(v) << std::endl; // Outputs 3.14
v = "Hello, world";
std::cout << std::get<std::string>(v) << std::endl; // Outputs Hello, world
// Safe Access
try {
std::cout << std::get<float>(v) << std::endl; // Attempt to get float, but current is std::string, will throw exception
} catch (const std::bad_variant_access& e) {
std::cout << e.what() << std::endl; // Outputs exception message
}
// Using visit
std::visit([](auto&& arg) {
std::cout << arg << std::endl;
}, v); // Safely prints the currently stored value, which is "Hello, world"
return 0;
}
In this example, std::variant is used to store an int, a float, and a std::string. It demonstrates how to safely use std::get to access data in std::variant, and how to use std::visit to apply a function or visitor to the stored value.
Real Environment#
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);
}
This code demonstrates how to use std::variant and std::visit to handle different types of resources. Here, the ResourceManager::flipResource method takes a parameter of type ResourceVariant named resource and returns a ResourceVariant of the same type. This ResourceVariant is a std::variant type that can contain different resource types (such as IMAGE or Atlas).