std::variant 是 C++17 引入的类型安全联合体,完全替代裸 union,内部维护活跃索引和类型信息,支持 std::get(编译期/运行期检查)和 std::visit(泛型类型分发),避免未定义行为。

std::variant 是 C++17 引入的类型安全联合体,它能完全替代裸 union,同时避免手动管理类型、防止未定义行为,并支持访问时的类型检查。
为什么不能直接用裸 union?
裸 union 不记录当前存储的是哪个成员,也不自动调用构造/析构函数。写入一个成员后读取另一个,或忘记调用析构函数,都会导致未定义行为。std::variant 内部维护 active index 和类型信息,确保每次访问都合法。
基本用法:声明、构造和访问
声明一个可容纳 int、double 或 std::string 的 variant:
using MyVariant = std::variant构造时自动推导活跃类型:
立即学习“C++免费学习笔记(深入)”;
MyVariant v1 = 42; // 活跃类型:intMyVariant v2 = 3.14; // 活跃类型:double
MyVariant v3 = "hello"; // 活跃类型:std::string
安全访问需用 std::get(编译期检查)或 std::visit(运行期分发):
- 用 std::get
(v) 获取指定类型的值(若类型不匹配,抛 std::bad_variant_access) - 用 std::get
(v) 按索引获取(索引从 0 开始,越界同样抛异常) - 更推荐 std::visit —— 类型安全、无需硬编码分支,天然支持所有可能类型
用 std::visit 处理多种类型(推荐方式)
std::visit 接收一个可调用对象(如 lambda)和一个或多个 variant,自动根据当前活跃类型调用对应逻辑:
std::visit([](const auto& val) {if constexpr (std::is_same_v<:decay_t>, int>) {
std::cout } else if constexpr (std::is_same_v<:decay_t>, double>) {
std::cout } else {
std::cout }
}, v);
也可用重载的 struct 实现更清晰的分派逻辑,尤其适合多 variant 场景。
处理无效状态与默认构造
std::variant 默认构造会尝试构造其第一个类型(若该类型可默认构造)。如果首类型不可默认构造,variant 就不可默认构造。为避免意外,可显式初始化:
std::variant<:monostate int std::string> v{}; // std::monostate 表示空状态v = 100; // 现在活跃类型是 int
检查是否为空用 v.index() == 0(当 std::monostate 是首类型时),或用 std::holds_alternative<:monostate>(v)。









