I need to serialize / deserialize a struct that has an optional member.
I’m using the excellent nlohmann::json
library and from the docs I can see that it should be done like this:
namespace nlohmann {
template <typename T> struct adl_serializer<std::optional<T>> {
static void to_json(json& j, const std::optional<T>& opt)
{
if (not opt.has_value()) {
j = nullptr;
}
else {
j = *opt; // this will call adl_serializer<T>::to_json which will
// find the free function to_json in T's namespace!
}
}
static void from_json(const json& j, std::optional<T>& opt)
{
if (j.is_null()) {
opt = std::nullopt;
}
else {
opt = j.template get<T>(); // same as above, but with
// adl_serializer<T>::from_json
}
}
};
} // namespace nlohmann
Now, ordinary conversions like these works:
std::optional<int32_t> opt_int{25};
j["k"] = opt_int.template<std::optional<int32_t>>;
and vice versa
// note: no value in j
nlohmann::json j;
// this now calls from_json
std::optional<int> o = j["k"].get<std::optional<int>>();
However, creating a struct and using https://json.nlohmann.me/api/macros/nlohmann_define_type_non_intrusive/:
struct TestStruct {
int32_t i;
std::optional<int32_t> j;
};
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(TestStruct, i, j);
Will now access the json
keys with the at()
call, yielding an exception:
nlohmann::json j = {
{"i", 15}
};
// exception
auto ts = j.template get<TestStruct>();
Is it not possible to handle this when using NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE
, so that if the key is absent, we just assign std::nullopt
?