Replies: 1 comment
-
I tried to implement this and added some new tests. The work is still in progress, but now user can add serialization function like this: namespace ns
{
struct animal
{
int m_age;
std::string m_name;
animal() : m_age(), m_name() {}
// member function, parse from j to *this
void from_json(const json& j)
{ /* code */ }
// static member function, parse from j to a
static void from_json(const json& j, animal& a)
{ /* code */ }
};
// free function, same as static member version
void from_json(const json& j, animal& a)
{ /* code */ }
} // namespace ns If we call get() this way: auto animal = json.get<ns::animal>();
// or get_to()
ns::animal animal;
json.get_to(animal); then the user defined function will be selected from these three functions, top to bottom Also a user can define type other way, without the default constructor: namespace ns {
struct animal
{
int m_age;
std::string m_name;
animal(const int& a, const std::string& n) : m_age(a), m_name(n) {}
animal() = delete;
static animal from_json(const json& j)
{ return /* code */; }
};
// adl_tag required for argument-dependent lookup
animal from_json(const json& j, nlohmann::adl_tag<animal>)
{ return /* code */; }
} // namespace ns
// ...
auto animal = json.get<ns::animal>(); As above, function will be selected from these two, top to bottom I am planning to add more tests and allow passing additional arguments for something like this: auto animal = json.get<ns::animal>(logging::verbose); The following questions are currently unclear to me:
|
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
I started working on extending of customization points for user-defined
from_json()
and I think this is a good point to discuss about interfaceCode example:
Only
№3
can be called now and it's unusable for non-default constructible/non-copyable types just nowBut we can extend our
adl_serializer
to support all four. How will different calls ofj.get()
work?j.get(v /*, args... */)
=v.from_json(j /*, args... */)
, calls№1
j.get<MyType>(/* args... */)
=MyType::from_json(j, /* args... */)
, calls№2
But when we comment out first and second functions, then:
j.get(v /*, args... */)
=from_json(j, v /*, args... */)
, calls№3
j.get<MyType>(/* args... */)
=from_json(j, /*, args..., */ nlohman::adl_tag<MyType>{})
, calls№4
This behaviour is slightly different from current state because
№4
has more priority than№3
. So, for compatibility, we can comment out№4
and now:j.get<MyType>()
=from_json(j, default_constructed_MyClass)
Can new behaviour of lookup for
№4
break existing code?To break existing code, user must have function overload with
nlohman::adl_tag<MyType>
, which is not possible because there was no such template beforeBut, yes, user can have existing both
from_json(json, MyType&)
and staticMyType::from_json(json)
at same time. I think this is possibly. how likely is it?.. Can this break code? ..№3
instead of compilation error? It's the bestWhy not just specialize
adl_serializer
?I think specialization of
adl_serializer
is always worse than member/free function (what can be found directly in user provided type or via ADL) because:№3
), in most cases this is not neededadl_serializer
specializationI'll try to implement this based on my previous PR, also for
try_deserialize()
(there will be the same possible ways to extend serialization support for third-party types except third function becase this is meaningless)to_json()
?Beta Was this translation helpful? Give feedback.
All reactions