命名空间
变体
操作

std::variant

来自 cppreference.cn
< cpp‎ | 工具
 
 
 
 
定义于头文件 <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显式部分特化,则程序是病态的,无需诊断。

目录

[编辑] 模板参数

类型 - 此变体中可能存储的类型。所有类型都必须满足 可析构 (Destructible) 要求(特别是,不允许数组类型和非对象类型)。

[编辑] 成员函数

构造 variant 对象
(公共成员函数) [编辑]
销毁 variant 及其包含的值
(公共成员函数) [编辑]
赋值一个 variant
(公共成员函数) [编辑]
观察器
返回 variant 所持可选类型的零基索引
(公共成员函数) [编辑]
检查 variant 是否处于无效状态
(公共成员函数) [编辑]
修改器
variant 中原地构造一个值
(公共成员函数) [编辑]
与另一个 variant 交换
(公共成员函数) [编辑]
访问(Visitation)
(C++26)
使用 variant 持有的参数调用提供的函数对象
(公共成员函数) [编辑]

[编辑] 非成员函数

(C++17)
用一个或多个 variant 所持有的参数调用所提供的函数对象
(函数模板) [编辑]
检查 variant 当前是否持有给定类型
(函数模板) [编辑]
根据索引或类型(如果类型唯一)读取变体的值,出错时抛出异常
(函数模板) [编辑]
(C++17)
根据索引或类型(如果唯一)获取指向被指向 variant 值的指针,出错时返回 null
(函数模板) [编辑]
(C++17)(C++17)(C++17)(C++17)(C++17)(C++17)(C++20)
variant 对象与其包含的值进行比较
(函数模板) [编辑]
特化 std::swap 算法
(函数模板) [编辑]

[编辑] 辅助类

(C++17)
用作非默认可构造类型变体的第一个替代项的占位符类型
(类) [编辑]
variant 的值进行无效访问时抛出的异常
(类) [编辑]
在编译时获取 `variant` 替代列表的大小
(类模板) (变量模板)[编辑]
在编译时根据索引获取可选类型的类型
(类模板) (别名模板)[编辑]
std::variant 的哈希支持
(类模板特化) [编辑]

[编辑] 辅助对象

无效状态下 variant 的索引
(常量) [编辑]

[编辑] 注意

特性测试 标准 特性
__cpp_lib_variant 201606L (C++17) std::variant: 一个类型安全的联合体
202102L (C++23)
(DR17)
用于从 std::variant 派生类的 std::visit
202106L (C++23)
(DR20)
完全 constexprstd::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++ 标准。

缺陷报告 应用于 发布时的行为 正确的行为
LWG 2901 C++17 提供了 std::uses_allocator 的特化,
variant 无法正确支持分配器
特化已移除
LWG 3990 C++17 程序可以声明 std::variant 的显式或
部分特化
在这种情况下程序是病态的
(无需诊断)
LWG 4141 C++17 对存储的要求
令人困惑
包含的对象必须
嵌套在 variant 对象中

[编辑] 另请参见

原地构造标签
(标签)[编辑]
(C++17)
可能包含或不包含对象的包装器
(类模板) [编辑]
(C++17)
保存任意 可复制构造 类型实例的对象
(类) [编辑]