如何在 C++ 中 serialize/deserialize std::map<int, MyObject> to/from json

How to serialize/deserialize std::map<int, MyObject> to/from json in C++

我正在尝试 serialize/deserialize std::map<int, MyObject> 使用 https://github.com/nlohmann/json

它说 here 地图的键必须能够生成 std::string。我怎样才能做到这一点?

实现转换的基本用法 to/from 我的自定义对象 MyObject 将是:

using nlohmann::json;

namespace ns {
    void to_json(json& j, const MyObject& p) {
        j = json{{"name", p.name}, {"address", p.address}, {"age", p.age}};
    }

    void from_json(const json& j, MyObject& p) {
        j.at("name").get_to(p.name);
        j.at("address").get_to(p.address);
        j.at("age").get_to(p.age);
    }
} // namespace ns

但是我应该为地图做什么?我最不想做的就是实现 void to_json(json& j, const std::map<int, MyObject>& p)void from_json(const json& j, std::map<int, MyObject>& p) 。由于库已经支持 std::map,它应该为我做所有事情,我只需要将 int 转换为 std::string。我该怎么做?

自述文件中的措辞清楚地说明了为什么这不起作用(强调我的):

Likewise, any associative key-value containers ... whose keys can construct an std::string and whose values can be used to construct JSON values ... can be used to create a JSON object.

这就是为什么使用 int 作为键不适用于此库的原因;不能从 int.

构造 std::string

自然的 follow-up 问题是 为什么 这是不允许的。这是你必须向图书馆的作者寻求明确答案的事情。

我们可以推测这是因为没有一种方法可以将整数转换为字符串。也许假设没有前导零的 10 进制表示是一个合理的选择,但没有令人信服的理由说明为什么这必须是唯一的选择。

hex-encoded 字符串、科学计数法、千位分隔符或任何可能数量的其他选项呢?

另一个可能的原因是整数键暗示一个稀疏数组,因此可能不清楚您请求在输出中生成对象还是数组。


一个可能的解决方案是构建一个助手,通过 运行 键通过 std::to_string():

将任何映射转换为 std::map<std::string, TValue>
// Copy variant
template <typename T>
std::map<std::string, typename T::mapped_type> to_string_keyed_map(T const & input) {
    std::map<std::string, typename T::mapped_type> output;

    for (auto const & pair : input) {
        output.emplace(std::to_string(pair.first), pair.second);
    }

    return output;
}

// Move variant
template <typename T>
std::map<std::string, typename T::mapped_type> to_string_keyed_map(T && input) {
    std::map<std::string, typename T::mapped_type> output;

    for (auto & pair : input) {
        output.emplace(std::to_string(pair.first), std::move(pair.second));
    }

    return output;
}