使用NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE处理含std::optional成员的结构体序列化问题
解决nlohmann::json中含std::optional成员结构体的反序列化键缺失问题
问题根源在于NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE宏默认使用at()方法访问JSON键,当键不存在时会直接抛出异常,无法自动给std::optional成员赋值std::nullopt。要实现需求,最直接的方式是手动实现结构体的序列化/反序列化函数,替代宏定义的自动生成逻辑,具体操作如下:
1. 定义目标结构体
假设我们有如下包含std::optional成员的结构体:
#include <nlohmann/json.hpp> #include <optional> #include <string> using json = nlohmann::json; struct MyStruct { int id; // 必选字段 std::optional<std::string> name; // 可选字段 std::optional<int> value; // 可选字段 };
2. 手动实现from_json和to_json函数
- 反序列化(from_json):对必选字段用
at()确保存在(缺失时抛异常),对可选字段通过find()或contains()判断键是否存在,不存在则赋值std::nullopt:
void from_json(const json& j, MyStruct& s) { // 必选字段强制校验,缺失则抛出异常 j.at("id").get_to(s.id); // 处理可选字段name:键存在则反序列化,否则设为nullopt auto name_it = j.find("name"); if (name_it != j.end()) { name_it->get_to(s.name); } else { s.name = std::nullopt; } // 处理可选字段value:更简洁的写法 s.value = j.contains("value") ? j["value"].get<std::optional<int>>() : std::nullopt; }
- 序列化(to_json):仅序列化
std::optional中有值的成员,避免JSON中出现多余的null键:
void to_json(json& j, const MyStruct& s) { j["id"] = s.id; if (s.name) { j["name"] = *s.name; } if (s.value) { j["value"] = *s.value; } }
3. 验证效果
当反序列化缺少可选字段的JSON时,对应std::optional成员会自动被设为std::nullopt,不会抛出异常。例如:
// 缺少name字段的JSON json j = R"({"id": 123, "value": 456})"_json; MyStruct s = j.get<MyStruct>(); // s.name == std::nullopt,s.value == 456,s.id == 123
由于你已经实现了std::optional的adl_serializer,上述代码中的get_to()和get<std::optional<T>>()会正常处理JSON null与std::nullopt的转换。
内容的提问来源于stack exchange,提问作者SupAl
相关产品推荐
相关产品推荐

