有没有办法用 nlohmann_json 库序列化异构向量?
Is there a way to serialize a heterogenous vector with nlohmann_json lib?
嗨 Stack Overflow 社区!
我正在开发一个大量使用有趣的 nlohmann_json
库的项目,看来我需要在特定 class 上添加继承 link,哪些对象被序列化在某一刻。
我尝试了在图书馆的 github 问题页面上找到的不同建议,但无法实现。
这是我试过的伪代码:
#include <nlohmann/json.hpp>
#include <iostream>
#include <memory>
#include <vector>
using json = nlohmann::json;
namespace nlohmann {
template <typename T>
struct adl_serializer<std::unique_ptr<T>> {
static void to_json(json& j, const std::unique_ptr<T>& opt) {
if (opt) {
j = *opt.get();
} else {
j = nullptr;
}
}
};
}
class Base {
public:
Base() = default;
virtual ~Base() = default;
virtual void foo() const { std::cout << "Base::foo()" << std::endl; }
};
class Obj : public Base
{
public:
Obj(int i) : _i(i) {}
void foo() const override { std::cout << "Obj::foo()" << std::endl; }
int _i = 0;
friend std::ostream& operator<<(std::ostream& os, const Obj& o);
};
std::ostream& operator<<(std::ostream& os, const Base& o)
{
os << "Base{} ";
return os;
}
std::ostream& operator<<(std::ostream& os, const Obj& o)
{
os << "Obj{"<< o._i <<"} ";
return os;
}
void to_json(json& j, const Base& b)
{
std::cout << "called to_json for Base" << std::endl;
}
void to_json(json& j, const Obj& o)
{
std::cout << "called to_json for Obj" << std::endl;
}
int main()
{
std::vector<std::unique_ptr<Base>> v;
v.push_back(std::make_unique<Base>());
v.push_back(std::make_unique<Obj>(5));
v.push_back(std::make_unique<Base>());
v.push_back(std::make_unique<Obj>(10));
std::cout << v.size() << std::endl;
json j = v;
}
// Results in :
// Program returned: 0
// 4
// called to_json for Base
// called to_json for Base
// called to_json for Base
// called to_json for Base
(https://gcc.godbolt.org/z/dc8h8f)
我知道 adl_serializer
只在调用时获得类型 Base
,但我不知道如何让他也知道类型 Obj
...
有人看到我在这里遗漏了什么吗?
提前感谢您的建议和帮助!
nlohmann.json不包括多态序列化,但是你可以在专门的adl_serializer
中自己实现。在这里,我们存储并检查了一个额外的 _type
JSON 字段,用作映射到每个派生类型的 type-erased from/to 函数对的键。
namespace PolymorphicJsonSerializer_impl {
template <class Base>
struct Serializer {
void (*to_json)(json &j, Base const &o);
void (*from_json)(json const &j, Base &o);
};
template <class Base, class Derived>
Serializer<Base> serializerFor() {
return {
[](json &j, Base const &o) {
return to_json(j, static_cast<Derived const &>(o));
},
[](json const &j, Base &o) {
return from_json(j, static_cast<Derived &>(o));
}
};
}
}
template <class Base>
struct PolymorphicJsonSerializer {
// Maps typeid(x).name() to the from/to serialization functions
static inline std::unordered_map<
char const *,
PolymorphicJsonSerializer_impl::Serializer<Base>
> _serializers;
template <class... Derived>
static void register_types() {
(_serializers.emplace(
typeid(Derived).name(),
PolymorphicJsonSerializer_impl::serializerFor<Base, Derived>()
), ...);
}
static void to_json(json &j, Base const &o) {
char const *typeName = typeid(o).name();
_serializers.at(typeName).to_json(j, o);
j["_type"] = typeName;
}
static void from_json(json const &j, Base &o) {
_serializers.at(j.at("_type").get<std::string>().c_str()).from_json(j, o);
}
};
用法:
// Register the polymorphic serializer for objects derived from `Base`
namespace nlohmann {
template <>
struct adl_serializer<Base>
: PolymorphicJsonSerializer<Base> { };
}
// Implement `Base`'s from/to functions
void to_json(json &, Base const &) { /* ... */ }
void from_json(json const &, Base &) { /* ... */ }
// Later, implement `Obj`'s from/to functions
void to_json(json &, Obj const &) { /* ... */ }
void from_json(json const &, Obj &) { /* ... */ }
// Before any serializing/deserializing of objects derived from `Base`, call the registering function for all known types.
PolymorphicJsonSerializer<Base>::register_types<Base, Obj>();
// Works!
json j = v;
注意事项:
typeid(o).name()
在实践中是唯一的,但不能保证符合标准。如果这是一个问题,它可以替换为任何持久运行时类型识别方法。
错误处理已被忽略,但 _serializers.at()
将在尝试序列化未知类型时抛出 std::out_of_range
。
此实现要求 Base
类型使用 ADL from/to
函数实现其序列化,因为它接管了 nlohmann::adl_serializer<Base>
.
嗨 Stack Overflow 社区!
我正在开发一个大量使用有趣的 nlohmann_json
库的项目,看来我需要在特定 class 上添加继承 link,哪些对象被序列化在某一刻。
我尝试了在图书馆的 github 问题页面上找到的不同建议,但无法实现。
这是我试过的伪代码:
#include <nlohmann/json.hpp>
#include <iostream>
#include <memory>
#include <vector>
using json = nlohmann::json;
namespace nlohmann {
template <typename T>
struct adl_serializer<std::unique_ptr<T>> {
static void to_json(json& j, const std::unique_ptr<T>& opt) {
if (opt) {
j = *opt.get();
} else {
j = nullptr;
}
}
};
}
class Base {
public:
Base() = default;
virtual ~Base() = default;
virtual void foo() const { std::cout << "Base::foo()" << std::endl; }
};
class Obj : public Base
{
public:
Obj(int i) : _i(i) {}
void foo() const override { std::cout << "Obj::foo()" << std::endl; }
int _i = 0;
friend std::ostream& operator<<(std::ostream& os, const Obj& o);
};
std::ostream& operator<<(std::ostream& os, const Base& o)
{
os << "Base{} ";
return os;
}
std::ostream& operator<<(std::ostream& os, const Obj& o)
{
os << "Obj{"<< o._i <<"} ";
return os;
}
void to_json(json& j, const Base& b)
{
std::cout << "called to_json for Base" << std::endl;
}
void to_json(json& j, const Obj& o)
{
std::cout << "called to_json for Obj" << std::endl;
}
int main()
{
std::vector<std::unique_ptr<Base>> v;
v.push_back(std::make_unique<Base>());
v.push_back(std::make_unique<Obj>(5));
v.push_back(std::make_unique<Base>());
v.push_back(std::make_unique<Obj>(10));
std::cout << v.size() << std::endl;
json j = v;
}
// Results in :
// Program returned: 0
// 4
// called to_json for Base
// called to_json for Base
// called to_json for Base
// called to_json for Base
(https://gcc.godbolt.org/z/dc8h8f)
我知道 adl_serializer
只在调用时获得类型 Base
,但我不知道如何让他也知道类型 Obj
...
有人看到我在这里遗漏了什么吗?
提前感谢您的建议和帮助!
nlohmann.json不包括多态序列化,但是你可以在专门的adl_serializer
中自己实现。在这里,我们存储并检查了一个额外的 _type
JSON 字段,用作映射到每个派生类型的 type-erased from/to 函数对的键。
namespace PolymorphicJsonSerializer_impl {
template <class Base>
struct Serializer {
void (*to_json)(json &j, Base const &o);
void (*from_json)(json const &j, Base &o);
};
template <class Base, class Derived>
Serializer<Base> serializerFor() {
return {
[](json &j, Base const &o) {
return to_json(j, static_cast<Derived const &>(o));
},
[](json const &j, Base &o) {
return from_json(j, static_cast<Derived &>(o));
}
};
}
}
template <class Base>
struct PolymorphicJsonSerializer {
// Maps typeid(x).name() to the from/to serialization functions
static inline std::unordered_map<
char const *,
PolymorphicJsonSerializer_impl::Serializer<Base>
> _serializers;
template <class... Derived>
static void register_types() {
(_serializers.emplace(
typeid(Derived).name(),
PolymorphicJsonSerializer_impl::serializerFor<Base, Derived>()
), ...);
}
static void to_json(json &j, Base const &o) {
char const *typeName = typeid(o).name();
_serializers.at(typeName).to_json(j, o);
j["_type"] = typeName;
}
static void from_json(json const &j, Base &o) {
_serializers.at(j.at("_type").get<std::string>().c_str()).from_json(j, o);
}
};
用法:
// Register the polymorphic serializer for objects derived from `Base`
namespace nlohmann {
template <>
struct adl_serializer<Base>
: PolymorphicJsonSerializer<Base> { };
}
// Implement `Base`'s from/to functions
void to_json(json &, Base const &) { /* ... */ }
void from_json(json const &, Base &) { /* ... */ }
// Later, implement `Obj`'s from/to functions
void to_json(json &, Obj const &) { /* ... */ }
void from_json(json const &, Obj &) { /* ... */ }
// Before any serializing/deserializing of objects derived from `Base`, call the registering function for all known types.
PolymorphicJsonSerializer<Base>::register_types<Base, Obj>();
// Works!
json j = v;
注意事项:
typeid(o).name()
在实践中是唯一的,但不能保证符合标准。如果这是一个问题,它可以替换为任何持久运行时类型识别方法。错误处理已被忽略,但
_serializers.at()
将在尝试序列化未知类型时抛出std::out_of_range
。此实现要求
Base
类型使用 ADLfrom/to
函数实现其序列化,因为它接管了nlohmann::adl_serializer<Base>
.