std::variant

来自cppreference.com
< cpp‎ | utility
 
 
工具库
通用工具
日期和时间
函数对象
格式化库 (C++20)
(C++11)
关系运算符 (C++20 中弃用)
整数比较函数
(C++20)(C++20)(C++20)
(C++20)
swap 与类型运算
(C++14)
(C++11)
(C++11)
(C++11)
(C++17)
常用词汇类型
(C++11)
(C++17)
(C++17)
variant
(C++17)
(C++11)
(C++17)
(C++23)
初等字符串转换
(C++17)
(C++17)
 
 
在标头 <variant> 定义
template< class... Types >
class variant;
(C++17 起)

类模板 std::variant 表示一个类型安全的联合体(以下称“变化体”)。std::variant 的一个实例在任意时刻要么保有它的一个可选类型之一的值,要么在错误情况下无值(此状态难以达成,见 valueless_by_exception)。

与联合体的行为一致,如果变化体保有某个对象类型 T 的值,那么 T 的对象表示会在变化体自身的对象表示中直接分配。不允许变化体分配额外的(动态)内存。

变化体不能保有引用、数组,或类型 void。空变化体也非良构(可用 std::variant<std::monostate> 代替)。

变化体可以保有同一类型多于一次,而且可保有同一类型的不同 cv 限定版本。

与联合体在聚合初始化中的行为一致,默认构造的变化体保有它的首个选项的值,除非该选项不可默认构造(此时该变化体也不可默认构造)。能用辅助类 std::monostate 使这种变化体可默认构造。

模板形参

Types - 可在此变化体中存储的类型。所有类型必须可析构 (Destructible) (特别是不允许数组类型和非对象类型)。

成员函数

构造 variant 对象
(公开成员函数)
析构 variant 和它包含的值
(公开成员函数)
赋值 variant
(公开成员函数)
观察器
返回 variant 所保有可选项的零基下标
(公开成员函数)
检查 variant 是否在非法状态
(公开成员函数)
修改器
原位构造 variant 中的值
(公开成员函数)
与另一 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++17)
(DR)
std::visit: 用于 std::variant 的访问者
202106L (C++20)
(DR)
完全 constexprstd::variant

示例

#include <cassert>
#include <string>
#include <variant>
 
int main()
{
    std::variant<int, float> v, w;
    v = 12; // v 含 int
    int i = std::get<int>(v);
    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&) {}
 
    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 的特化,但 std::variant 不能正确支持分配器 移除该特化

参阅

原位构造标签
(类模板)
(C++17)
可能或可能不保有一个对象的包装器
(类模板)
(C++17)
可保有任何可复制构造 (CopyConstructible) 类型的实例的对象。
(类)