std::variant
出自 cppreference.com
| 定義於標頭 <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 所持有的引數呼叫提供的函子(函式樣板) |
| (C++17) |
檢查 variant 目前是否持有給定型別(函式樣板) |
| (C++17) |
根據索引或型別(若型別唯一)讀取 variant 的值,錯誤時拋出例外 (函式樣板) |
| (C++17) |
根據索引或型別(若唯一)取得所指 variant 值的指標,錯誤時回傳 null(函式樣板) |
| (C++17)(C++17)(C++17)(C++17)(C++17)(C++17)(C++20) |
比較 variant 物件與其包含的值(函式樣板) |
| (C++17) |
特化 std::swap 演算法 (函式樣板) |
[edit] 輔助類別
| (C++17) |
用作無法預設建構型別的 variant 中第一個替代型別的佔位符型別(類別) |
| (C++17) |
存取 variant 值無效時拋出的例外(類別) |
| (C++17) |
在編譯時期取得 variant 的替代型別列表大小(類別樣板) (變數樣板) |
| 在編譯時期取得由索引指定的替代型別 (類別樣板) (別名樣板) | |
| (C++17) |
針對 std::variant 的雜湊 (hash) 支援 (類別樣板特例化) |
[edit] 輔助物件
| (C++17) |
處於無效狀態的 variant 之索引(常數) |
[edit] 附註
| 功能測試巨集 | 數值 | 標準 | 功能 |
|---|---|---|---|
__cpp_lib_variant |
201606L |
(C++17) | std::variant:一種型別安全的 union |
202102L |
(C++23) (DR17) |
針對衍生自 std::variant 之類別的 std::visit | |
202106L |
(C++23) (DR20) |
完全 constexpr 的 std::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 型別實例的物件 (類別) |