std::variant
来自cppreference.com
在标头 <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) | 以给定索引或类型(如果类型唯一)读取 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::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 含 intint 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(conststd::bad_variant_access& ex){std::cout<< ex.what()<<'\n';} usingnamespace std::literals; std::variant<std::string> x("abc");// 转换构造函数在无歧义时起作用 x ="def";// 转换赋值在无歧义时亦起作用 std::variant<std::string, voidconst*> y("abc");// 传递 char const* 时转换成 void const*assert(std::holds_alternative<voidconst*>(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) 类型的实例的对象。 (类) |