命名空間
變體
動作

std::variant

出自 cppreference.com
< cpp‎ | 工具
 
 
 
 
定義於標頭 <variant>
template< class... Types >
class variant;
(自 C++17 起)

類別樣板 std::variant 代表一個型別安全的 union

variant 的實體在任何給定時間,要么持有其替代型別之一的值,要么在發生錯誤的情況下不持有值(此狀態很難達成,請參閱 valueless_by_exception)。

與 union 一樣,如果 variant 持有某個物件型別 T 的值,則該 T 物件會嵌套在 variant 物件內。

variant 不允許持有參考、陣列或 void 型別。

variant 允許多次持有相同的型別,也允許持有同一型別的不同 cv 限定版本。

與 union 在聚合初始化 (aggregate initialization) 時的行為一致,預設建構的 variant 會持有其第一個替代型別的值,除非該替代型別無法預設建構(在這種情況下,variant 也無法預設建構)。輔助類別 std::monostate 可用於使此類 variant 能夠被預設建構。

若程式將 std::variant 定義實例化且未提供任何樣板引數,則該程式格式錯誤。此時可改用 std::variant<std::monostate>

如果程式宣告了 std::variant顯式 (explicit)部分 (partial) 特化,則程式格式錯誤,無需診斷。

目錄

[edit] 樣板參數

型別 - 可能存儲在此 variant 中的型別。所有型別必須滿足 可解構 (Destructible) 要求(特別是,不允許使用陣列型別和非物件型別)。

[edit] 成員函式

建構 variant 物件
(公開成員函式) [編輯]
解構 variant 以及其包含的值
(公開成員函式) [編輯]
指派一個 variant
(公開成員函式) [編輯]
觀察器
傳回 variant 當前持有的替代型別之從零開始的索引
(公開成員函式) [編輯]
檢查 variant 是否處於無效狀態
(公開成員函式) [編輯]
修改器
原地建構 variant 中的值
(公開成員函式) [編輯]
與另一個 variant 交換
(公開成員函式) [編輯]
訪問 (Visitation)
(C++26)
variant 所持有的引數呼叫提供的函子 (functor)
(公開成員函式) [編輯]

[edit] 非成員函式

(C++17)
以一個或多個 variant 所持有的引數呼叫提供的函子
(函式樣板) [編輯]
檢查 variant 目前是否持有給定型別
(函式樣板) [編輯]
根據索引或型別(若型別唯一)讀取 variant 的值,錯誤時拋出例外
(函式樣板) [編輯]
(C++17)
根據索引或型別(若唯一)取得所指 variant 值的指標,錯誤時回傳 null
(函式樣板) [編輯]
(C++17)(C++17)(C++17)(C++17)(C++17)(C++17)(C++20)
比較 variant 物件與其包含的值
(函式樣板) [編輯]
特化 std::swap 演算法
(函式樣板) [編輯]

[edit] 輔助類別

(C++17)
用作無法預設建構型別的 variant 中第一個替代型別的佔位符型別
(類別) [編輯]
存取 variant 值無效時拋出的例外
(類別) [編輯]
在編譯時期取得 variant 的替代型別列表大小
(類別樣板) (變數樣板)[編輯]
在編譯時期取得由索引指定的替代型別
(類別樣板) (別名樣板)[編輯]
針對 std::variant 的雜湊 (hash) 支援
(類別樣板特例化) [編輯]

[edit] 輔助物件

處於無效狀態的 variant 之索引
(常數) [編輯]

[edit] 附註

功能測試巨集 數值 標準 功能
__cpp_lib_variant 201606L (C++17) std::variant:一種型別安全的 union
202102L (C++23)
(DR17)
針對衍生自 std::variant 之類別的 std::visit
202106L (C++23)
(DR20)
完全 constexprstd::variant
202306L (C++26) 成員 visit

[edit] 範例

#include <cassert>
#include <iostream>
#include <string>
#include <variant>
 
int main()
{
    std::variant<int, float> v, w;
    v = 42; // v contains int
    int i = std::get<int>(v);
    assert(42 == i); // succeeds
    w = std::get<int>(v);
    w = std::get<0>(v); // same effect as the previous line
    w = v; // same effect as the previous line
 
//  std::get<double>(v); // error: no double in [int, float]
//  std::get<3>(v);      // error: valid index values are 0 and 1
 
    try
    {
        std::get<float>(w); // w contains int, not float: will throw
    }
    catch (const std::bad_variant_access& ex)
    {
        std::cout << ex.what() << '\n';
    }
 
    using namespace std::literals;
 
    std::variant<std::string> x("abc");
    // converting constructors work when unambiguous
    x = "def"; // converting assignment also works when unambiguous
 
    std::variant<std::string, void const*> y("abc");
    // casts to void const* when passed a char const*
    assert(std::holds_alternative<void const*>(y)); // succeeds
    y = "xyz"s;
    assert(std::holds_alternative<std::string>(y)); // succeeds
}

可能輸出

std::get: wrong index for variant

[edit] 缺陷報告

下列更改行為的缺陷報告追溯應用於之前的 C++ 標準。

DR 應用於 出版時的行為 正確的行為
LWG 2901 C++17 提供了 std::uses_allocator 的特化,
variant 無法正確支援配置器 (allocator)
移除特化
LWG 3990 C++17 程式若宣告了顯式或
部分特化 std::variant
在這種情況下程式格式錯誤
(無需診斷)
LWG 4141 C++17 關於存儲的規範
配置 (allocation) 描述易造成混淆
所包含的物件必須
嵌套在 variant 物件內

[edit] 參閱

就地建構標籤
(標籤)[編輯]
(C++17)
一個可能持有也可能不持有物件的封裝器
(類別模板) [編輯]
(C++17)
持有任何 CopyConstructible 型別實例的物件
(類別) [編輯]
English Deutsch 日本語 中文(简体) 中文(繁體)