std::variant是C++17引入的类型安全可变容器,编译期确定类型列表,运行时仅持一个活跃值并自动管理生命周期;支持构造、std::get/holds_alternative安全访问及std::visit模式匹配处理。

std::variant 是 C++17 引入的类型安全的“可变类型容器”,可以看作是带类型检查、自动管理生命周期的现代 union。它不是运行时动态类型,而是在编译期确定所有可能类型,运行时只持有一个活跃值,并确保析构和访问都安全。
基本用法:定义、构造和访问
声明一个 variant,需明确列出所有允许的类型(最多 16 个,具体取决于实现):
示例:
std::variant
立即学习“C++免费学习笔记(深入)”;
你可以用初始化列表、赋值或 std::make_variant_alternative(不常用)来构造:
- v = 42; → 活跃类型变为 int
- v = std::string{"hello"}; → 自动析构旧值,构造新 string
- v = 3.14; → 活跃类型变为 double
安全获取值:std::get 和 std::holds_alternative
直接用 std::get
更推荐先判断再取值:
- if (std::holds_alternative<:string>(v)) { ... }
- auto& s = std::get<:string>(v); // 此时已确保安全
也可用 std::get_if
统一处理多种类型:std::visit
这是 variant 最强大的用法——类似“模式匹配”,对当前活跃值执行对应逻辑,无需手动 if-else 判断类型。
写法一:lambda(推荐)
std::visit([](const auto& x) {
if constexpr (std::is_same_v<:decay_t>, int>) {
std::cout } else if constexpr (std::is_same_v<:decay_t>, std::string>) {
std::cout }
}, v);
写法二:自定义 visitor 结构体(适合复用)
struct Printer {
void operator()(int i) const { std::cout void operator()(const std::string& s) const { std::cout void operator()(double d) const { std::cout };
std::visit(Printer{}, v);
注意事项与常见坑
- variant 不支持 void 或引用类型作为备选项(但可存 std::reference_wrapper)
- 所有备选项必须满足可析构、可移动(多数情况也要求可复制),否则编译失败
- 默认构造只对第一个类型生效;若首类型不可默认构造,需显式初始化
- 使用 std::monostate 可表示“空状态”(如 std::variant<:monostate int std::string>)
基本上就这些。std::variant 不复杂,但容易忽略类型安全和访问方式的选择。用好它,能显著减少手工管理 union 的错误,让多态数据结构更清晰、更健壮。









