std::variant
定义于头文件 <variant>
。
声明
template< class... Types >
class variant;
类模板 std::variant 表示一个类型安全的联合体。std::variant 的实例在任何给定时间要么持有一个其替代类型之一的值,要么在出错时——不持有任何值(这种状态很难达到,参见 valueless_by_exception)。
与联合体一样,如果一个变体持有某个对象类型 T 的值,则 T 的对象表示会直接分配在变体自身的内部对象表示中。变体不允许分配额外的(动态)内存。
变体不允许持有引用、数组或 void 类型。空变体也是不合法的(可以使用 std::variant<std::monostate>
代替)。
变体允许多次持有相同的类型,并持有相同类型的不同 cv-qualified 版本。
与联合体在聚合初始化期间的行为一致,默认构造的变体持有其第一个替代类型的值,除非该替代类型不可默认构造(在这种情况下,变体也不可默认构造)。辅助类 std::monostate 可用于使此类变体可默认构造。
模板参数
Types
- 可能存储在此变体中的类型。所有类型都必须满足可析构要求(特别是,不允许使用数组类型和非对象类型)。
成员函数
公共 | (构造函数) | 构造变体对象 (公共成员函数) |
公共 | (析构函数) | 销毁变体及其包含的值 (公共成员函数) |
公共 | operator= | 赋值一个变体 (公共成员函数) |
观察者
公共 | 索引 | 返回变体所持有的替代类型的基于零的索引 (公共成员函数) |
公共 | valueless_by_exception | 检查变体是否处于无效状态 (公共成员函数) |
修改器
公共 | emplace | 在变体中就地构造一个值 (公共成员函数) |
公共 | swap | 与另一个变体交换 (公共成员函数) |
非成员函数
公共 | visit (C++17) | 使用一个或多个变体持有的参数调用提供的函数对象 (函数模板) |
公共 | holds_alternative(C++17) | 检查变体当前是否持有给定类型 |
公共 | std::get(std::variant)(C++17) | 根据索引或类型(如果类型是唯一的)读取变体的值,出错时抛出异常 (函数模板) |
公共 | get_if(C++17) | 根据索引或类型(如果唯一)获取指向变体所指向的值的指针,出错时返回 null (函数模板) |
公共 | operator== (C++17) operator!= (C++17) operator< (C++17) operator<= (C++17) operator>(C++17) operator>= (C++17) operator<=> (C++20) | 比较变体对象,比较其包含的值 (函数模板) |
公共 | std::swap(std::variant)(C++17) | 特化 std::swap 算法 (函数模板) |
帮助类
公共 | monostate(C++17) | 用作不可默认构造类型变体的第一个替代类型的占位符类型 (类) |
公共 | bad_variant_access(C++17) | 对变体值进行无效访问时抛出的异常 (类) |
公共 | variant_size variant_size_v(C++17) | 在编译时获取变体(variant)替代方案列表的大小 (类模板) (变量模板) |
公共 | variant_alternative variant_alternative_t (C++17) | 在编译时根据索引获取替代类型的类型 (类模板) (别名模板) |
公共 | std::hash(std::variant)(C++17) | 特化 std::hash 算法 (类模板特化) |
辅助对象
公共 | variant_npos(C++17) | 变体处于无效状态时的索引 (常量) |
备注
特性测试宏 | 值 | 标准 | 注释 |
---|---|---|---|
__cpp_lib_variant | 201606L | (C++17) | std::variant:C++17 的类型安全联合体 |
__cpp_lib_variant | 202102L | (C++17) (DR) | std::visit 适用于派生自 std::variant 的类 |
__cpp_lib_variant | 202106L | (C++20) (DR) | 完全 constexpr 的 std::variant |
示例
#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 无法正确支持分配器 | 特化已移除 |