跳到主要内容
版本:Next

variant

std::variant 是 C++17 引入的类型安全的联合体(union),可以在编译期确定的多个类型中同时只持有其中一个值。它取代了 C 风格 union(后者不能持有非平凡类型如 std::string),也避免了手动 void* + 类型标签的不安全模式。

头文件与基本特征

#include <variant>
特征说明
作用类型安全的 union,某一时刻持有指定类型之一
类型检查编译期确定可选类型列表
访问方式get<T>()visit()
空状态valueless_by_exception 仅在异常构造失败时出现
存储分配足够容纳最大类型的栈内存

基本用法

#include <iostream>
#include <string>
#include <variant>

int main() {
std::variant<int, double, std::string> v;

v = 42;
std::cout << std::get<int>(v) << '\n'; // 42

v = std::string("hello");
std::cout << std::get<std::string>(v) << '\n'; // hello

return 0;
}

visit 访问模式

std::visit 是处理 variant 最安全的方式——编译期保证覆盖所有类型:

#include <iostream>
#include <string>
#include <variant>

struct Printer {
void operator()(int x) const { std::cout << "int: " << x << '\n'; }
void operator()(double x) const { std::cout << "double: " << x << '\n'; }
void operator()(const std::string& x) const { std::cout << "string: " << x << '\n'; }
};

int main() {
std::variant<int, double, std::string> v = 3.14;
std::visit(Printer{}, v); // double: 3.14
return 0;
}

常用接口

接口作用
get<T>()获取指定类型的值,类型错误抛 bad_variant_access
get_if<T>(&v)返回指针,类型不匹配返回 nullptr
index()当前持有类型的索引(0-based)
visit(visitor, v)用 visitor 处理 variant
emplace<T>(args...)原地构造新值
holds_alternative<T>()检查当前是否持有某类型

典型场景

  1. 解析结果:可能是值、错误码、或错误消息。
  2. 状态机:每个状态是不同类型,转换时切换。
  3. JSON 值:number / string / bool / null 的统一表示。

使用注意

  1. 优先用 visit 而不是 get,避免遗漏类型处理。
  2. 不要用 variant 装"50 种类型",那通常是设计问题。
  3. optional 区别:optional<T> 是"T 或空",variant<T1, T2, ...> 是"类型之一"。

小结

std::variant 给了 C++ 一个类型安全的 union,配合 std::visit 可实现编译期强制覆盖所有情况的模式匹配。它比裸 union 安全得多,也是很多设计模式(如结果、状态)的更好载体。