std::variant是编译期固定类型的安全联合体,声明必须穷举所有可能类型;访问需用std::visit或std::get,不支持隐式转换或解引用。

std::variant声明时必须指定所有可能类型
它不是运行时动态类型容器,而是在编译期就固定类型集合的“安全联合体”。声明漏掉任一可能类型,后续赋值就会编译失败。
- 正确写法:
std::variant<int std::string double> v;</int> - 如果后续想存
std::vector<int></int>,必须提前加进模板参数列表,否则v = std::vector<int>{1,2,3};</int>直接报错:no matching constructor - 类型重复(如
std::variant<int int></int>)不合法;但std::variant<int long></int>允许——虽然它们底层可能相同,但语义不同
访问值要用std::visit或std::get,不能直接解引用
直接写 v.value() 或 *v 是错的——std::variant 没有隐式转换,也不提供指针式访问接口。必须显式处理当前持有类型。
- 推荐用
std::visit:类型安全、支持 lambda、自动匹配当前 active 类型std::visit([](const auto& x) { std::cout << x; }, v); - 用
std::get<t>(v)</t>前必须确保v.index() == std::variant_alternative_t<t decltype></t>对应的索引,否则抛std::bad_variant_access -
std::get_if<int>(&v)</int>更安全:返回int*或nullptr,适合做类型检查分支
默认构造只对第一个可默认构造的类型生效
声明 std::variant<:string int std::monostate></:string> 后执行 std::variant<...> v;</...>,实际调用的是 std::string() 构造函数——因为它是首个可默认构造的类型。如果所有类型都不可默认构造,编译直接失败。
- 想强制初始化为某个特定类型,用
std::variant<int std::string> v{42};</int>或v.emplace<:string>("hi");</:string> - 加入
std::monostate是常见技巧:它空且可默认构造,能确保std::variant<:monostate t1 t2></:monostate>总能默认构造,并显式表示“未设置”状态 - 注意:
std::monostate不等于std::nullopt,它只是个占位类型,不带语义,需自行约定用途
和union、std::any、std::optional对比时别选错场景
它解决的是「有限、已知、异构类型集合」的值存储与访问问题。不是万能替代品。
立即学习“C++免费学习笔记(深入)”;
-
union:无类型安全,不管理构造/析构,std::variant自动调用对应类型的构造/析构函数 -
std::any:运行时擦除类型,类型信息仅在运行时检查,性能开销大,且取值必须用std::any_cast猜类型——适合完全未知类型;std::variant编译期约束,零成本抽象 -
std::optional<t></t>:只表达“T 有或没有”,不是“T 或 U 或 V”;三者嵌套(如std::optional<:variant std::string>></:variant>)才等价于“无 / int / string”


















