std::variant

来自cppreference.com
< cpp‎ | utility
 
 
 
 
在标头 <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 所保有的各实参调用所提供的函数对象
(函数模板) [编辑]
检查某个 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::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 含 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) 类型的实例的对象。
(类) [编辑]