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
的显式或部分特化,则程序是非良构的,无需诊断。
内容 |
[编辑] 模板参数
Types | - | 可能存储在此变体中的类型。所有类型都必须满足 Destructible 要求(特别是,不允许使用数组类型和非对象类型)。 |
[编辑] 成员函数
构造 variant 对象(公开成员函数) | |
销毁 variant ,以及其包含的值(公开成员函数) | |
赋值 variant (公开成员函数) | |
观察器 | |
返回 variant 持有的备选类型的从零开始的索引(公开成员函数) | |
检查 variant 是否处于无效状态(公开成员函数) | |
修改器 | |
在 variant 中就地构造一个值(公开成员函数) | |
与另一个 variant 交换(公开成员函数) | |
访问 | |
(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) |
占位符类型,用作非默认构造类型的 variant 中的第一个备选类型(类) |
(C++17) |
在无效访问 variant 的值时抛出的异常(类) |
(C++17) |
在编译时获取 variant 的备选类型列表的大小(类模板) (变量模板) |
在编译时获取由索引指定的备选类型的类型 (类模板) (别名模板) | |
(C++17) |
对 std::variant 的哈希支持 (类模板特化) |
[编辑] 辅助对象
(C++17) |
处于无效状态的 variant 的索引(常量) |
[编辑] 注解
特性测试 宏 | 值 | Std | 特性 |
---|---|---|---|
__cpp_lib_variant |
201606L |
(C++17) | std::variant : 类型安全的联合体 |
202102L |
(C++23) (DR17) |
std::visit 用于从 std::variant 派生的类 | |
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++ 标准。
DR | 应用于 | 已发布行为 | 正确行为 |
---|---|---|---|
LWG 2901 | C++17 | 提供了 std::uses_allocator 的特化, 但 variant 无法正确支持分配器 |
特化已移除 |
LWG 3990 | C++17 | 程序可以声明显式或std::variant 的部分特化 |
在这种情况下,程序是非良构的 情况(无需诊断) |
LWG 4141 | C++17 | 存储的要求 分配令人困惑 |
包含的对象必须 嵌套在 variant 对象内 |
[编辑] 参见
就地构造标签 (标签) | |
(C++17) |
一个可能持有也可能不持有对象的包装器 (类模板) |
(C++17) |
持有任何CopyConstructible 类型的实例的对象 (类) |