使用nlohmann json的to_json序列化Eigen Vec3d失效问题及from_json实现
Eigen Vec3d JSON序列化问题解决及反序列化实现
问题原因
你写的to_json模板函数没被调用,核心原因是nlohmann/json库对Eigen::Matrix类型有默认的序列化逻辑(转成JSON数组),而你的Vec3<T>本质是Eigen::Matrix的模板别名,编译器会优先匹配库自带的默认序列化,而非你定义的函数。另外,ADL(参数依赖查找)规则下,你的函数如果不在Eigen命名空间或自定义类型的命名空间里,也不会被优先选中。
解决方法
有两种可靠的修复方式:
方式1:将to_json放入Eigen命名空间
把你的序列化函数放到Eigen命名空间下,让ADL能正确找到它,覆盖默认的数组序列化:
#include <nlohmann/json.hpp> #include <Eigen/Core> template <typename T> using Vec3 = Eigen::Matrix<T, 1, 3, Eigen::DontAlign | Eigen::ColMajor>; using Vec3d = Vec3<double>; namespace Eigen { template <typename T> void to_json(nlohmann::json& j, const Matrix<T, 1, 3, Eigen::DontAlign | Eigen::ColMajor>& v) { j = {{"X", v(0)}, {"Y", v(1)}, {"Z", v(2)}}; } } // namespace Eigen // 使用示例 int main() { Vec3d test(1.0, 2.0, 3.0); nlohmann::json frameJson; frameJson["Vec3d"] = test; // 输出:{"Vec3d":{"X":1.0,"Y":2.0,"Z":3.0}} return 0; }
方式2:特化nlohmann::adl_serializer(推荐)
直接针对Vec3<T>特化nlohmann库的adl_serializer,不需要侵入Eigen命名空间,逻辑更清晰且优先级更高:
#include <nlohmann/json.hpp> #include <Eigen/Core> template <typename T> using Vec3 = Eigen::Matrix<T, 1, 3, Eigen::DontAlign | Eigen::ColMajor>; using Vec3d = Vec3<double>; namespace nlohmann { template <typename T> struct adl_serializer<Vec3<T>> { // 序列化:转成含X/Y/Z的JSON对象 static void to_json(json& j, const Vec3<T>& v) { j = {{"X", v(0)}, {"Y", v(1)}, {"Z", v(2)}}; } // 反序列化:从JSON对象还原Vec3<T> static void from_json(const json& j, Vec3<T>& v) { // 使用at()确保键不存在时抛出异常,如需容错可改用find() v(0) = j.at("X").template get<T>(); v(1) = j.at("Y").template get<T>(); v(2) = j.at("Z").template get<T>(); } }; } // namespace nlohmann // 使用示例 int main() { // 序列化 Vec3d test(1.0, 2.0, 3.0); nlohmann::json frameJson; frameJson["Vec3d"] = test; // 反序列化 Vec3d restored; restored = frameJson["Vec3d"].get<Vec3d>(); return 0; }
模板化adl_serializer from_json实现
上面的代码已经包含了完整的模板化反序列化逻辑,核心是通过j.at("X")获取JSON对象中的对应键值,再用get<T>()转换为目标类型,确保类型安全。如果需要容错处理(比如键不存在时赋默认值),可以修改为:
static void from_json(const json& j, Vec3<T>& v) { v(0) = j.contains("X") ? j["X"].template get<T>() : T{}; v(1) = j.contains("Y") ? j["Y"].template get<T>() : T{}; v(2) = j.contains("Z") ? j["Z"].template get<T>() : T{}; }
内容的提问来源于stack exchange,提问作者Nitron_707
相关产品推荐
相关产品推荐

