跳到主要内容

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_variant201606L(C++17)std::variant:C++17 的类型安全联合体
__cpp_lib_variant202102L(C++17) (DR)std::visit 适用于派生自 std::variant 的类
__cpp_lib_variant202106L(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 2901C++17提供了 std::uses_allocator 的特化,但 std::variant 无法正确支持分配器特化已移除

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_variant201606L(C++17)std::variant:C++17 的类型安全联合体
__cpp_lib_variant202102L(C++17) (DR)std::visit 适用于派生自 std::variant 的类
__cpp_lib_variant202106L(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 2901C++17提供了 std::uses_allocator 的特化,但 std::variant 无法正确支持分配器特化已移除