如何在C++中将std::map〈int,MyObject>序列化/反序列化到json/从json反序列化

cig3rfwq  于 2023-02-26  发布在  其他
关注(0)|答案(2)|浏览(341)

我正在尝试使用https://github.com/nlohmann/json序列化/反序列化std::map<int, MyObject>
这里说map的键必须能够生成std::string,我该怎么做呢?
实现与我的自定义对象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

但是我应该为Map做些什么呢?我最不想做的事情就是实现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。我该怎么做呢?

i86rm4rw

i86rm4rw1#

自述文件中的措辞很清楚地说明了为什么这不起作用(强调是我的):
同样,任何键-值关联容器......其键可以构造std::string,其值可以用于构造JSON值......都可以用于创建JSON对象。
这就是为什么使用int作为键不适用于此库的原因;不能从int构造std::string
接下来的问题自然是“为什么”不允许这样做,这是你必须向图书馆的作者寻求明确答案的问题。
我们可以推测,这是因为没有一种方法可以将整数转换为字符串,也许假设没有前导零的以10为基的表示法是一个合理的选择,但没有令人信服的理由说明这一定是唯一的选择。
那么十六进制编码的字符串、科学记数法、千位分隔符或者其他任何可能的选项呢?
另一个可能的原因是,整数键建议使用稀疏数组,因此可能不清楚在输出中请求的是对象还是数组。
一个可能的解决方案是构建一个helper,通过在std::to_string()中运行键来将任何Map转换为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;
}
zpgglvta

zpgglvta2#

下面是一个通用的解决方案:为任意std::map定义to_json()from_json()函数模板,如下所示:

template <typename KTy, typename VTy> inline
void to_json(nlohmann::json& j, const std::map<KTy, VTy>& m)
{
    using std::to_string;
    for (const auto& e : m)
    {
        j[to_string(e.first)] = e.second;
    }
}

template <typename KTy, typename VTy> inline
void from_json(const nlohmann::json& j, std::map<KTy, VTy>& m)
{
    for (const auto& e : j.items())
    {
        KeyTy k;
        from_string(e.key(), k);
        auto v = e.value().get<VTy>();
        m[k] = v;
    }
}

现在我们已经定义了一种将字符串值转换为Map的key_type(“反序列化”键)的方法,例如,可以使用from_string()函数模板来实现,如下所示:

// A generic implementation (stub).
template <typename Ty> inline
void from_string(const std::string& key, Ty& value)
{
    value = key;
}

template <> inline
void from_string(const std::string& key, int& value)
{
    char* endPtr = nullptr;
    val = std::strtol(key.c_str(), &endPtr, 10);
}
// Add more specializations for other key types here.

有了这些函数,以及定制类型的to/from_json()重载(来自原始问题),就可以用自然的方式在std::map和JSON之间进行转换了:

nlohmann::json j;
std::map<int, MyObject> myMap;
// ...
myMap = j.at("inputs").get<std::map<int, MyObject>>();
j = myMap;

相关问题