std::variant
来自 cppreference.com
定义在头文件 <variant> 中 |
||
template< class... Types > class variant; |
(自 C++17 起) | |
类模板 std::variant
表示一个类型安全的 联合。在任何给定时间,std::variant
的实例要么包含其备用类型之一的值,要么在错误的情况下不包含任何值(此状态很难实现,请参见 valueless_by_exception)。
与联合一样,如果变体包含某个对象类型 T
的值,则 T
对象 嵌套在 variant
对象本身中。不允许变体分配额外的(动态)内存。
变体不允许包含引用、数组或类型 void。
变体允许多次包含相同类型,并包含相同类型的不同 cv 限定版本。
与联合在 聚合初始化 期间的行为一致,默认构造的变体包含其第一个备用类型的值,除非该备用类型不可默认构造(在这种情况下,变体本身也不可默认构造)。辅助类 std::monostate 可用于使此类变体可默认构造。
使用没有模板参数的实例化 std::variant
定义的程序格式错误。可以使用 std::variant<std::monostate> 代替。
如果程序声明了 std::variant
的 显式 或 部分 特化,则该程序格式错误,不需要诊断。
内容 |
[编辑] 模板参数
类型 | - | 可以在此变体中存储的类型。所有类型都必须满足 可销毁 要求(特别是,不允许数组类型和非对象类型)。 |
[编辑] 成员函数
构造 variant 对象(公共成员函数) | |
销毁 variant ,以及其包含的值(公共成员函数) | |
分配 variant (公共成员函数) | |
观察者 | |
返回 variant 所包含的备用类型的零基索引(公共成员函数) | |
检查 variant 是否处于无效状态(公共成员函数) | |
修改器 | |
在 variant 中就地构造一个值(公共成员函数) | |
与另一个 variant 交换(公共成员函数) | |
访问 | |
(C++26) |
使用 variant 所包含的参数调用提供的函数对象(公共成员函数) |
[编辑] 非成员函数
(C++17) |
使用一个或多个 variant 所包含的参数调用提供的函数对象(函数模板) |
(C++17) |
检查 variant 是否当前包含给定类型(函数模板) |
(C++17) |
根据索引或类型(如果类型是唯一的)读取变体的值,在错误时抛出异常 (函数模板) |
(C++17) |
获取指向指向的 `variant` 的值的指针,根据索引或类型(如果唯一),在错误时返回空指针 (函数模板) |
(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++17) (DR) |
std::visit 用于从 std::variant 派生的类 | |
202106L | (C++20) (DR) |
完全 `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 的专门化, 但 `std::variant` 不能正确支持分配器 |
专门化已移除 |
LWG 3990 | C++17 | 程序可以声明 `std::variant` 的显式或 部分专门化 |
在这种情况下,程序是非法的(不需要诊断) case (no diagnostic required) |
[编辑] 另请参阅
就地构造标签 (标签) | |
(C++17) |
一个可能或不可能包含对象的包装器 (类模板) |
(C++17) |
包含任何 CopyConstructible 类型的实例的对象 (类) |