C++17 中的 std::variant 与 std::optional 的实用案例

在 C++17 之后,std::variantstd::optional 成为标准库中非常实用的类型,用来替代传统的裸指针或手动管理内存的方式。本文将通过一个具体的业务场景——实现一个简单的表单数据校验器,演示如何利用这两个类型提升代码安全性、可读性和维护性。

1. 背景:表单数据的多态结构

假设我们正在开发一个多租户系统,每个租户的表单字段类型各不相同:

  • 有的字段为字符串(如“用户名”)
  • 有的字段为整数(如“年龄”)
  • 有的字段可选(如“备注”)
  • 有的字段是枚举(如“性别”)

传统做法常用 void*boost::variant,需要显式检查类型并转换,容易出错。C++17 的 std::variant 可以直接把所有可能的类型打包在一个容器里,std::optional 则能自然表示“可选”字段。

2. 设计数据结构

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

// 枚举类型
enum class Gender { Male, Female, Other };

// 表单字段的值类型
using FieldValue = std::variant<
    std::string,          // 文本
    int,                  // 整数
    double,               // 浮点
    bool,                 // 布尔
    Gender,               // 枚举
    std::optional<std::string> // 可选文本
>;

// 表单字段描述
struct FieldDef {
    std::string name;
    bool required;
};

// 表单数据
using FormData = std::unordered_map<std::string, FieldValue>;
using FormDefs = std::vector <FieldDef>;

3. 解析与验证流程

3.1 解析

我们从 JSON(这里只用字符串演示)解析成 FormData。在解析过程中,根据字段名称判断应该存入哪种类型。

FieldValue parseField(const std::string& key, const std::string& value) {
    if (key == "age") {
        return std::stoi(value);
    } else if (key == "salary") {
        return std::stod(value);
    } else if (key == "gender") {
        if (value == "male") return Gender::Male;
        if (value == "female") return Gender::Female;
        return Gender::Other;
    } else if (key == "active") {
        return value == "true";
    } else {
        return value; // 默认文本
    }
}

3.2 验证

使用 std::variant 的 `std::holds_alternative

` 或 `std::visit` 进行类型检查,配合 `std::optional` 判断必填字段是否存在。 “`cpp bool validate(const FormDefs& defs, const FormData& data) { for (const auto& def : defs) { auto it = data.find(def.name); if (def.required && it == data.end()) { std::cerr (it->second)) { std::cerr (“首席研发”) } // 可选字段 }; // 3. 验证 if (validate(defs, data)) { std::cout ; if constexpr (std::is_same_v) std::cout ) std::cout ) std::cout ) std::cout ) { if (arg == Gender::Male) std::cout >) { if (arg) std::cout

发表评论