You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 10:33:17