通八洲科技

c++的std::variant怎么用 类型安全的union【详解】

日期:2025-12-24 00:00 / 作者:冰火之心
std::variant 是 C++17 引入的类型安全联合体,运行时明确持有且仅持有一种预定义类型,自动管理构造/析构、禁止隐式转换,并通过 std::visit 或 std::get 安全访问。

std::variant 是 C++17 引入的类型安全联合体(type-safe union),它能在一个对象中存储多种不同类型中的某一种,并在运行时明确知道当前存的是哪个类型,彻底避免了传统 union 的未定义行为和手动管理类型的麻烦。

核心特点:安全、明确、可访问

与裸 union 不同,std::variant 自动管理构造/析构、禁止隐式转换、提供编译期类型检查和运行时状态查询。它不是“多个值共存”,而是“**一个值,但可能是其中某一种类型**”。

基本用法:构造、赋值、获取值

构造方式灵活,支持直接初始化、拷贝/移动、甚至聚合初始化(C++20 起):

std::variant v1 = 42;           // 推导为 int
std::variant v2{"hello"};      // 推导为 string
std::variant v3 = std::string{"world"}; // 显式构造
v1 = std::string{"changed"};                    // 赋值会自动销毁旧值、构造新值

获取值推荐使用 std::get(v)std::get(v)(I 为索引),但需确保类型匹配:

安全访问:std::visit 是最佳实践

最推荐的方式是用 std::visit 配合 lambda 或函数对象——它自动分发到当前实际类型,类型安全且无需手动判断:

std::variant v = 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 << "string: " << x << '\n';
    } else if constexpr (std::is_same_v) {
        std::cout << "double: " << x << '\n';
    }
}, v);

这种写法利用了 C++17 的 constexpr if,在编译期裁剪分支,零开销且类型完整覆盖。也可以用重载的函数对象(如 struct Visitor { void operator()(int){} void operator()(const std::string&){} })。

常见陷阱与注意事项

std::variant 把“我存了什么”这个问题从程序员脑中搬进了类型系统里,配合 visit 就像给 union 装上了编译器级的 switch —— 写得清楚,跑得安心。