题目

编写程序,演示 C++17 引入的类型安全联合体 std::variant<Types...>。对比 C 语言传统裸联合体 union(无法管理带有构造/析构函数的非 POD 对象且缺乏类型追踪)的致命缺陷;展示 std::variant 原生支持 std::string、int、double 的安全共存;并使用基于现代函数式 Visitor 模式的 std::visit 配合重载 Lambda(Overload 模式匹配技巧)对变体内容进行穷举访问。

输入格式:无需外部输入。

输出格式:输出 variant 存放不同类型时的大小、当前类型索引与 std::visit 模式匹配回显。

数据范围与约定:可辨识联合(Tagged Union)、类型安全、std::visit 模式匹配。

思路与算法

1. 传统 union 的淘汰
C 语言 union 内部只是简单的内存重叠,程序员必须自己用一个外部 enum 记录当前存的是什么,若类型搞错会导致未定义内存解析崩溃;且不能存含析构函数的复杂 C++ 对象。

2. 可辨识联合(Tagged Union)
std::variant 内部除了最大成员的存储区外,还包含一个类型索引标记(index())。当尝试通过 std::get<int> 访问当前不是 int 的变体时,立即抛出 std::bad_variant_access。

3. Overloaded 结构体模式匹配
利用 C++17 结构体可变参数继承与推导指引:template<class... Ts> struct Overloaded : Ts... { using Ts::operator()...; };,可在 std::visit 中写出类似 Rust/Scala 模式匹配的代码。

完整程序

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

// 现代 C++17 Overload 模式匹配辅助模板工具
template<class... Ts> struct Overload : Ts... { using Ts::operator()...; };
template<class... Ts> Overload(Ts...) -> Overload<Ts...>;

// 定义一个类型安全的动态属性值联合体
using JsonPrimitive = std::variant<int, double, std::string, bool>;

int main() {
    std::cout << "std::variant 栈占用大小: " << sizeof(JsonPrimitive) 
              << " 字节 (最大成员 + 类型索引标记)\n\n";

    std::vector<JsonPrimitive> payloadList;
    payloadList.emplace_back(2026);                    // int
    payloadList.emplace_back(3.14159);                 // double
    payloadList.emplace_back(std::string("Cluster-A")); // std::string (传统 union 无法容纳)
    payloadList.emplace_back(true);                    // bool

    std::cout << "--- 使用 std::visit 进行强类型模式匹配分发 ---\n";
    for (const auto& item : payloadList) {
        std::visit(Overload{
            [](int arg) {
                std::cout << "[整型分支] 整数: " << arg << "\n";
            },
            [](double arg) {
                std::cout << "[浮点分支] 浮点: " << arg << "\n";
            },
            [](const std::string& arg) {
                std::cout << "[字符串分支] 长度: " << arg.length() << " -> 内容: \"" << arg << "\"\n";
            },
            [](bool arg) {
                std::cout << "[布尔分支] 状态: " << (arg ? "TRUE" : "FALSE") << "\n";
            }
        }, item);
    }

    return 0;
}

运行示例

输出:

std::variant 栈占用大小: 40 字节 (最大成员 + 类型索引标记)

--- 使用 std::visit 进行强类型模式匹配分发 ---
[整型分支] 整数: 2026
[浮点分支] 浮点: 3.14159
[字符串分支] 长度: 9 -> 内容: "Cluster-A"
[布尔分支] 状态: TRUE