std::variant
来自 cppreference.cn
定义于头文件 <variant> |
||
template< class... Types > class variant; |
(C++17 起) | |
类模板 std::variant
表示一个类型安全的 联合体。
variant
的实例在任何给定时间要么持有一个其可选类型之一的值,要么在发生错误时 - 不持任何值(这种状态很难达到,参见 valueless_by_exception)。
与联合体一样,如果变体持有一个某种对象类型 T
的值,则 T
对象会嵌套在 variant
对象内。
变体不允许持有引用、数组或 void 类型。
变体允许多次持有相同的类型,以及持有相同类型的不同 cv 限定版本。
与联合体在聚合初始化期间的行为一致,默认构造的变体持有其第一个可选类型的值,除非该可选类型不可默认构造(在这种情况下,变体也不可默认构造)。辅助类 std::monostate 可以用于使此类变体可默认构造。
用无模板参数实例化 std::variant
定义的程序是病态的。可以改用 std::variant<std::monostate>。
如果程序声明了 std::variant
的显式或部分特化,则程序是病态的,无需诊断。
目录 |
[编辑] 模板参数
类型 | - | 此变体中可能存储的类型。所有类型都必须满足 可析构 (Destructible) 要求(特别是,不允许数组类型和非对象类型)。 |
[编辑] 成员函数
构造 variant 对象(公共成员函数) | |
销毁 variant 及其包含的值(公共成员函数) | |
赋值一个 variant (公共成员函数) | |
观察器 | |
返回 variant 所持可选类型的零基索引(公共成员函数) | |
检查 variant 是否处于无效状态(公共成员函数) | |
修改器 | |
在 variant 中原地构造一个值(公共成员函数) | |
与另一个 variant 交换(公共成员函数) | |
访问(Visitation) | |
(C++26) |
使用 variant 持有的参数调用提供的函数对象(公共成员函数) |
[编辑] 非成员函数
(C++17) |
用一个或多个 variant 所持有的参数调用所提供的函数对象(函数模板) |
(C++17) |
检查 variant 当前是否持有给定类型(函数模板) |
(C++17) |
根据索引或类型(如果类型唯一)读取变体的值,出错时抛出异常 (函数模板) |
(C++17) |
根据索引或类型(如果唯一)获取指向被指向 variant 值的指针,出错时返回 null(函数模板) |
(C++17)(C++17)(C++17)(C++17)(C++17)(C++17)(C++20) |
将 variant 对象与其包含的值进行比较(函数模板) |
(C++17) |
特化 std::swap 算法 (函数模板) |
[编辑] 辅助类
(C++17) |
用作非默认可构造类型变体的第一个替代项的占位符类型 (类) |
(C++17) |
对 variant 的值进行无效访问时抛出的异常(类) |
(C++17) |
在编译时获取 `variant` 替代列表的大小 (类模板) (变量模板) |
在编译时根据索引获取可选类型的类型 (类模板) (别名模板) | |
(C++17) |
对 std::variant 的哈希支持 (类模板特化) |
[编辑] 辅助对象
(C++17) |
无效状态下 variant 的索引(常量) |
[编辑] 注意
特性测试宏 | 值 | 标准 | 特性 |
---|---|---|---|
__cpp_lib_variant |
201606L |
(C++17) | std::variant : 一个类型安全的联合体 |
202102L |
(C++23) (DR17) |
用于从 std::variant 派生类的 std::visit | |
202106L |
(C++23) (DR20) |
完全 constexpr 的 std::variant | |
202306L |
(C++26) | 成员 visit |
[编辑] 示例
运行此代码
#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
[编辑] 缺陷报告
下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。
缺陷报告 | 应用于 | 发布时的行为 | 正确的行为 |
---|---|---|---|
LWG 2901 | C++17 | 提供了 std::uses_allocator 的特化, 但 variant 无法正确支持分配器 |
特化已移除 |
LWG 3990 | C++17 | 程序可以声明 std::variant 的显式或部分特化 |
在这种情况下程序是病态的 (无需诊断) |
LWG 4141 | C++17 | 对存储的要求 令人困惑 |
包含的对象必须 嵌套在 variant 对象中 |
[编辑] 另请参见
原地构造标签 (标签) | |
(C++17) |
可能包含或不包含对象的包装器 (类模板) |
(C++17) |
保存任意 可复制构造 类型实例的对象 (类) |