电话
400 9058 355
应使用 std::variant 替代裸 union,它类型安全、自动管理生命周期;声明需显式列出非重复的可选类型,初始化支持默认、直接和 in_place_type 三种方式;读取必须用 std::get(可能抛异常)或更推荐的 std::visit(编译期全覆盖、无异常)。
直接用 std::variant 替代裸 union,它能自动管理类型生命周期、禁止非法访问,并在编译期约束可选类型——这是 C++17 引入类型安全联合体的唯一正统方式。
std::variant 是一个模板类,必须显式列出所有允许的类型。它不接受重复类型,也不支持 void 或引用类型(但可存 int& 的包装如 std::reference_wrapper)。
常见错误:写成 std::variant(重复类型编译失败),或试图 std::variant(auto 不合法)。
初始化方式有三种:
std::variant 默认构造为 int{}
std::variant v{42}; ,编译器按参数类型推导并调用对应分支std::in_place_type_t 显式指定:如 std::variant<:string double> v{std::in_place_type<:string>, "hello"},适合需要带参构造的类型不能像裸 union 那样直接 reinterpret_cast 或强制访问。必须通过 std::get 或 std::visit —— 否则触发未定义行为(UB)。
std::get 在运行时检查当前存储类型是否为 T,若不是则抛出 std::bad_variant_access。适用于已知类型且愿意处理异常的场景。
std::visit 是更推荐的方式,它把类型分发逻辑交给编译器,天然覆盖所有可能分支
,且无异常开销:
std::variantv = 3.14; std::visit([](const auto& x) { using T = std::decay_t ; if constexpr (std::is_same_v ) { std::cout << "int: " << x << "\n"; } else if constexpr (std::is_same_v ) { std::cout << "double: " << x << "\n"; } else if constexpr (std::is_same_v ) { std::cout << "string: " << x << "\n"; } }, v);
注意:lambda 必须是泛型(auto&),且内部要用 if constexpr 做编译期分支,否则会实例化所有分支导致编译失败(比如对 int 调用 .size())。
用 v.index() 获取当前类型的零基序号(从 0 开始),或用 v.valueless_by_exception() 判断是否因异常中途构造失败(极少见,通常发生在某类型移动构造抛异常时)。
更实用的是 std::holds_alternative,返回 bool 表示是否正存储 T:
v.index() == 1 更可读、不易出错if (std::holds_alternative<:string>(v)) { /* 安全 get */ }
v;多线程下仍需额外同步它不是语法糖,底层实现通常包含一个类型标签 + 内联缓冲区(类似 std::optional),所以大小是各类型大小的最大值加上一个字节(用于 tag)。这意味着:
std::variant 变得臃肿,慎用于高频小对象场景variant 进入 valueless 状态(v.valueless_by_exception() == true),再次访问前必须重赋值constexpr 构造(C++20 起部分支持),若需编译期确定类型,请考虑 std::variant 配合 if constexpr,而非运行时 std::visit
真正难处理的点不在语法,而在于类型集合设计:一旦定义了 std::variant,后续新增类型就必须改所有 std::visit 分支和 std::holds_alternative 判断——这本质上是一种有限制的代数数据类型(ADT),扩展性弱于动态类型系统,但换来的是编译期安全和零运行时成本。
邮箱:8955556@qq.com
Q Q:8955556
本文详解如何将Go官方present工具(用于生成HTML5...
PySNMP在不同版本中对SNMP错误状态(errorSta...
time.Sleep仅阻塞当前goroutine,其他gor...
PHPfopen()创建含特殊符号的文件名失败主因是操作系统...
WooCommerce中通过代码为分组产品动态聚合子商品的属...
io.ReadFull返回io.ErrUnexpectedE...
本文详解Yii2中控制器向视图传递ActiveRecord数...
本文详解为何通过wp_set_object_terms()为...
Pytest中使用@mock.patch类装饰器会导致补丁泄...
带缓冲的channel是并发安全的FIFO队列;make(c...