我想用nlohmann-json序列化一个std::optional<float>
。
文档中给出的boost::optional
示例似乎非常接近我想要的,但我不明白我对它的适应哪里出错了。
反序列化组件似乎在为我工作,但不是to_json方面。
下面是一个最小的工作示例
// OptionalSeriealisationTest.cpp
//#define JSON_USE_IMPLICIT_CONVERSIONS 0
// Tried toggling this as per this comment
// https://github.com/nlohmann/json/issues/1749#issuecomment-772996219 with no effect
// (no effect noticed)
#include <iostream>
#include <optional>
#include <nlohmann/json.hpp>
namespace nlohmann
{
template <typename T>
struct adl_serializer<std::optional<T>>
{
// This one is the issue
static void to_json(json& j, const std::optional<T>& opt) {
//if (opt == std::nullopt) {
// 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!
//}
if (opt)
{
j = opt.value();
}
else
{
j = nullptr;
}
//NB same errors on the block above and the commented-out version
}
static void from_json(const json& j, std::optional<T>& opt) {
if (j.is_null()) {
opt = std::nullopt;
}
else {
opt = j.get<T>(); // same as above, but with
// adl_serializer<t>::from_json
}
}
};
}
using json = nlohmann::ordered_json;
int main()
{
{
// Seems ok, breakpoints on the from_json are hit
json j;
j["x"] = 4.0f;
std::optional<float> x;
j.at("x").get_to<std::optional<float>>(x);
std::cout << x.has_value() << std::endl;
std::cout << x.value() << std::endl;
}
{
// Seems ok, breakpoints on the from_json are hit
json j;
j["x"] = nullptr;
std::optional<float> x = 4.0f;
j.at("x").get_to<std::optional<float>>(x);
std::cout << x.has_value() << std::endl;
//std::cout << x.value() << std::endl;
}
{
// Won't compile on MSVC
std::optional<float> x = 4.0;
json j;
j["x"] = x;
}
{
// Won't compile on MSVC
std::optional<float> x = 4.0;
auto j = json({ "x", x });
}
}
to_json
方面将无法在MSVC中编译,出现以下错误
Severity Code Description Project File Line Suppression State
Error (active) E0289
no instance of constructor
"nlohmann::basic_json<ObjectType, ArrayType, StringType,
BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType,
AllocatorType, JSONSerializer, BinaryType>::basic_json
[with ObjectType=nlohmann::ordered_map, ArrayType=std::vector,
StringType=std::string, BooleanType=bool, NumberIntegerType=int64_t,
NumberUnsignedType=uint64_t, NumberFloatType=double,
AllocatorType=std::allocator, JSONSerializer=nlohmann::adl_serializer,
BinaryType=std::vector<uint8_t, std::allocator<uint8_t>>]"
matches the argument list
我的具体要求是
- 如何修复?
- 为什么这会出错,当它看起来如此接近他们的例子(boost::optional vs std::optional?)
我注意到关于将std::optionals
纳入lib本身的麻烦的项目有一些相当长的讨论,尽管我不完全遵循它并理解它对我来说在实践中想要使用std::optional
作为第三方对象意味着什么。的一些评论建议的方法类似于我在这里工作,所以我希望它相当于一个监督/愚蠢的错误。
干杯!
这是一个很难发现的东西,因为你太担心它是深奥的东西。这可能是相当具体到我的错误,不会太可能使用任何人在未来发现这一点。尽管如此,答案如下:
我的MWE是对真实代码库中的某些东西的简化。代码库专门使用orderd_json
,但简称为json
,即
using json = nlohmann::ordered_json;
在nlohmann
中使用json
这个词的类是一个不同的、更一般的类。看起来,当序列化到ordered_json
时,它需要专门针对ordered_json
类型,并且不能自动导入。
。我应该让to_json
接受类型ordered_json
作为它的第一个参数。
static void to_json(ordered_json& j, const std::optional<T>& opt) {/*...*/}
而不是
static void to_json(json& j, const std::optional<T>& opt) {/*...*/}
事实证明from_json
无论如何都能工作。