std:: variant
|
定义于头文件
<variant>
|
||
|
template
<
class
...
Types
>
class variant ; |
(C++17 起) | |
类模板
std::variant
表示一个类型安全的
联合体
。
在任何给定时刻,
variant
实例要么持有其某个备选类型的值,要么在错误情况下不持有任何值(这种状态很难达成,参见
valueless_by_exception
)。
与联合体类似,若 variant 持有某个对象类型
T
的值,则该
T
对象会
嵌套在
variant
对象内部。
variant 不允许持有引用、数组或 void 类型。
一个 variant 允许多次持有相同类型,并且可以持有同一类型的不同 cv 限定版本。
与 聚合初始化 期间联合体的行为一致,默认构造的 variant 持有其首个可选项的值,除非该可选项不可默认构造(此时该 variant 也不可默认构造)。辅助类 std::monostate 可用于使此类 variant 可默认构造。
一个使用无模板参数的
std::variant
定义进行实例化的程序是病式的。
std
::
variant
<
std::
monostate
>
可以作为替代方案使用。
如果程序声明了
std::variant
的
显式
或
部分
特化,则该程序非良构,不要求诊断。
目录 |
模板参数
| 类型 | - | 可存储于此 variant 中的类型。所有类型必须满足 Destructible 要求(特别地,不允许数组类型和非对象类型)。 |
成员函数
构造
variant
对象
(公开成员函数) |
|
销毁
variant
及其所含值
(公开成员函数) |
|
赋值
variant
(公开成员函数) |
|
观察器 |
|
返回
variant
所持有可选项的基于零的索引
(公开成员函数) |
|
检查
variant
是否处于无效状态
(公开成员函数) |
|
修改器 |
|
原位构造
variant
中的值
(公开成员函数) |
|
与另一
variant
交换
(公开成员函数) |
|
访问 |
|
|
(C++26)
|
以
variant
所持参数调用提供的函数对象
(公开成员函数) |
非成员函数
|
(C++17)
|
以
variant
对象持有的参数调用提供的函数对象
(函数模板) |
|
(C++17)
|
检查
variant
是否当前持有给定类型
(函数模板) |
|
(C++17)
|
通过索引或类型(若类型唯一)读取
variant
的值,错误时抛出异常
(函数模板) |
|
(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
处于无效状态的索引
(常量) |
注释
| 功能测试 宏 | 值 | 标准 | 功能特性 |
|---|---|---|---|
__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 包含 int int i = std::get<int>(v); assert(42 == i); // 成功 w = std::get<int>(v); w = std::get<0>(v); // 与上一行效果相同 w = v; // 与上一行效果相同 // std::get<double>(v); // 错误:[int, float] 中无 double 类型 // std::get<3>(v); // 错误:有效索引值为 0 和 1 try { std::get<float>(w); // w 包含 int 而非 float:将抛出异常 } catch (const std::bad_variant_access& ex) { std::cout << ex.what() << '\n'; } using namespace std::literals; std::variant<std::string> x("abc"); // 转换构造函数在无歧义时生效 x = "def"; // 转换赋值在无歧义时同样生效 std::variant<std::string, void const*> y("abc"); // 传入 char const* 时转换为 void const* assert(std::holds_alternative<void const*>(y)); // 成功 y = "xyz"s; assert(std::holds_alternative<std::string>(y)); // 成功 }
可能的输出:
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)
|
可容纳任意
CopyConstructible
类型实例的对象
(类) |