c++17中引入了std::variant。std::variant類似union。
定義於頭文件 <variant>。
類模板 std::variant 表示一個類型安全的聯合體。 std::variant 的一個實例在任意時刻要麼保有其一個可選類型之一的值,要麼在錯誤情況下無值(此狀態難以達成,見 valueless_by_exception )。
與聯合體在聚合初始化中的行爲一致, 若 variant 保有某個對象類型 T 的值,則直接於 variant 的對象表示中分配 T 的對象表示。不允許 variant 分配額外的(動態)內存。
variant 不容許保有引用、數組,或類型 void 。空 variant 亦爲病式(可用 std::variant<std::monostate> 代替)。
variant 容許保有同一類型多於一次,而且可保有同一類型的不同 cv 限定版本。
同聯合體,默認構造的 variant 保有其首個選項的值,除非該選項不是可默認構造的(該情況下 variant 亦非可默認構造:能用輔助類 std::monostate 使這種 variant 可默認構造)。
簡單示例:
using IntFloatString = std::variant<int, float, std::string>; // 定義支持int、float、string三個類型,並取一個別名
//初始化一個variant
TEST_F(InitVariant) {
IntFloatString i = 10;
ASSERT_EQ(10, std::get<int>(i) );
IntFloatString f = 20.0f;
ASSERT_EQ(20.0f, std::get<float>(f) );
IntFloatString s = "hello world";
ASSERT_EQ("hello world", std::get<std::string>(s));
}
模板形參
Types - 可存儲於此 variant 中的類型。所有類型必須滿足可析構 (Destructible) 要求(特別是不允許數組類型和非對象類型)。
成員函數
(構造函數):構造 variant 對象(公開成員函數)
(析構函數):析構 variant 同其所含的值(公開成員函數)
operator=:賦值 variant(公開成員函數)
觀察器
index:返回 variant 所保有可選項的零基下標(公開成員函數)
valueless_by_exception:檢查 variant 是否在非法狀態(公開成員函數)
修改器
emplace:原位構造 variant 中的值(公開成員函數)
swap:與另一 variant 交換(公開成員函數)
實例
#include <variant>
#include <string>
#include <cassert>
int main()
{
std::variant<int, float> v, w;
v = 12; // v 含 int
int i = std::get<int>(v);
w = std::get<int>(v);
w = std::get<0>(v); // 與前一行效果相同
w = v; // 與前一行效果相同
// std::get<double>(v); // 錯誤: [int, float] 中無 double
// std::get<3>(v); // 錯誤:合法下標值爲 0 與 1
try {
std::get<float>(w); // w 含 int 而非 float :將拋出
}
catch (const std::bad_variant_access&) {}
using namespace std::literals;
std::variant<std::string> x("abc"); // 轉換構造函數在無歧義時起作用
x = "def"; // 轉換賦值在無歧義時亦起作用
std::variant<std::string, void const*> y("abc");
// 傳遞 char const * 時轉換成 void const *
assert(std::holds_alternative<void const*>(y)); // 成功
y = "xyz"s;
assert(std::holds_alternative<std::string>(y)); // 成功
}
可以看看:
https://github.com/boostorg/variant/tree/develop/include/boost