std::variant は C++17 標準で導入された union で、std::variant は 1 つの変数に異なる型のデータを格納し、型安全を維持することができます。これは従来の 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)を含むことができます。