【C++】C++17 std::variant的用法

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

參考

https://zh.cppreference.com/w/cpp/utility/variant

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章