nlohmann JSON中模板类from_json/to_json序列化反序列化报错排查
解决nlohmann JSON模板类序列化/反序列化的编译错误
问题根源分析
你的代码存在三个核心问题,导致编译失败:
- 缺少
Test类的序列化逻辑:仅为Test的adl_serializer特化了from_json反序列化函数,但未提供对应的to_json序列化函数,编译器无法将Test对象转换为JSON对象。 Data类未实现to_json函数:尝试序列化Data时,编译器自动生成的默认逻辑无法处理Test成员,触发类型匹配错误。SetCurrentOutput存在空值风险:直接调用std::optional::value()会在可选值为空时触发未定义行为,且原方法的参数类型与成员变量不匹配。
解决方案及修正代码
以下是完整的修正代码,包含所有问题的修复:
#include <vector> #include <optional> #include <iostream> #include <memory> #include <Eigen/Dense> #include <nlohmann/json.hpp> using json = nlohmann::json; template <class InputType = float, class OutputType = bool> class Test { public: struct InputOutputPair { InputType input; OutputType output; }; void SetLeftThreshold(InputType threshold) { m_leftThreshold = threshold; } void SetRightThreshold(InputType threshold) { m_rightThreshold = threshold; } // 修正参数类型:与成员变量OutputType匹配 void SetLeftOutput(OutputType output) { m_leftOutput = output; } // 修正参数类型:与成员变量OutputType匹配 void SetRightOutput(OutputType output) { m_rightOutput = output; } void SetThresholdsMidpoint(InputType midThreshold) { m_thresholdsMidpoint = midThreshold; } // 修复空值处理逻辑:避免直接调用value()导致崩溃 void SetCurrentOutput(std::optional<OutputType> currentOutput) { m_currentOutput = currentOutput; } // 添加getter方法,用于序列化时访问私有成员 InputType GetLeftThreshold() const { return m_leftThreshold; } InputType GetRightThreshold() const { return m_rightThreshold; } OutputType GetLeftOutput() const { return m_leftOutput; } OutputType GetRightOutput() const { return m_rightOutput; } InputType GetThresholdsMidpoint() const { return m_thresholdsMidpoint; } const std::optional<OutputType>& GetCurrentOutput() const { return m_currentOutput; } private: // 初始化成员变量,避免未定义值 InputType m_leftThreshold{}; InputType m_rightThreshold{}; OutputType m_leftOutput{}; OutputType m_rightOutput{}; InputType m_thresholdsMidpoint{}; std::optional<OutputType> m_currentOutput{}; }; class Data { public: Test<> m_leftSwitch; }; // 实现Data的反序列化 inline void from_json(const json& j, Data& hsd) { j.at("isLeftSwitch").get_to(hsd.m_leftSwitch); } // 实现Data的序列化 inline void to_json(json& j, const Data& hsd) { j = {{"isLeftSwitch", hsd.m_leftSwitch}}; } namespace nlohmann { template <class InputType, class OutputType> struct adl_serializer<Test<InputType, OutputType>> { // 反序列化逻辑:显式指定类型转换,避免隐式转换歧义 inline static void from_json(const json& j, Test<InputType, OutputType>& hsd) { hsd.SetLeftThreshold(j.at("leftThreshold").get<InputType>()); hsd.SetRightThreshold(j.at("rightThreshold").get<InputType>()); hsd.SetLeftOutput(j.at("leftOutput").get<OutputType>()); hsd.SetRightOutput(j.at("rightOutput").get<OutputType>()); hsd.SetThresholdsMidpoint(j.at("thresholdMidPoint").get<InputType>()); // 处理可选值:兼容JSON中键不存在或为null的情况 hsd.SetCurrentOutput(j.value("currentOutput", std::nullopt)); } // 补全序列化逻辑:映射Test成员到JSON键值对 inline static void to_json(json& j, const Test<InputType, OutputType>& hsd) { j = { {"leftThreshold", hsd.GetLeftThreshold()}, {"rightThreshold", hsd.GetRightThreshold()}, {"leftOutput", hsd.GetLeftOutput()}, {"rightOutput", hsd.GetRightOutput()}, {"thresholdMidPoint", hsd.GetThresholdsMidpoint()}, {"currentOutput", hsd.GetCurrentOutput()} }; } }; } // namespace nlohmann int main() { // 测试序列化 Data data; data.m_leftSwitch.SetLeftThreshold(1.0f); data.m_leftSwitch.SetRightThreshold(2.0f); data.m_leftSwitch.SetLeftOutput(true); data.m_leftSwitch.SetRightOutput(false); data.m_leftSwitch.SetThresholdsMidpoint(1.5f); data.m_leftSwitch.SetCurrentOutput(true); json j = data; std::cout << "Serialized JSON:\n" << j.dump(4) << std::endl; // 测试反序列化 Data new_data; from_json(j, new_data); std::cout << "\nDeserialized left threshold: " << new_data.m_leftSwitch.GetLeftThreshold() << std::endl; }
关键修正点说明
- 补全
Test的序列化逻辑:在adl_serializer中添加to_json函数,通过getter方法访问私有成员,完成JSON映射。 - 修复参数类型不匹配:将
SetLeftOutput/SetRightOutput的参数类型从InputType改为OutputType,与成员变量类型一致。 - 完善可选值处理:使用
json::value()方法兼容currentOutput键不存在或为null的场景,避免空optional的非法访问。 - 初始化成员变量:为
Test的私有成员添加默认初始化,避免序列化时出现不确定值。
内容的提问来源于stack exchange,提问作者Nitron_707
相关产品推荐
相关产品推荐

