Namespaces
Variants

std:: variant

From cppreference.net
Utilities library
定义于头文件 <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 对象持有的参数调用提供的函数对象
(函数模板)
检查 variant 是否当前持有给定类型
(函数模板)
通过索引或类型(若类型唯一)读取 variant 的值,错误时抛出异常
(函数模板)
(C++17)
通过索引或类型(若唯一)获取指向 variant 值的指针,错误时返回空指针
(函数模板)
(C++17) (C++17) (C++17) (C++17) (C++17) (C++17) (C++20)
以所含值比较 variant 对象
(函数模板)
特化 std::swap 算法
(函数模板)

辅助类

(C++17)
用作非默认构造类型 variant 中首个可选类型的占位符类型
(类)
访问 variant 值时抛出异常
(类)
在编译时获取 variant 可选类型列表的大小
(类模板) (变量模板)
在编译时通过索引获取对应可选类型的类型
(类模板) (别名模板)
std::variant 提供哈希支持
(类模板特化)

辅助对象

表示 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 类型实例的对象
(类)