Boost变体:如何对JSON建模

Boost Variant: How to model JSON?

本文关键字:JSON 建模 变体 Boost      更新时间:2023-10-16

我正在尝试使用Boost Spirit将JSON对象存储为递归数据结构来解析JSON字符串:

Value <== [null, bool, long, double, std::string, Array, Object];
Array <== [Value, Value, Value, ...];
Object <== ["name1": Value, "name2": Value, ...];

这是我的代码:

#include <map>
#include <vector>
#include <string>
#include <boost/variant.hpp>
#include <boost/shared_array.hpp>
#include <boost/shared_ptr.hpp>
struct JsonNull {};
struct JsonValue;
typedef std::map<std::string, JsonValue *> JsonObject;
typedef std::vector<JsonValue *> JsonArray;
struct JsonValue : boost::variant<JsonNull, bool, long, double, std::string, JsonArray, JsonObject>
{
};
JsonValue aval = JsonObject();

编译时我得到错误:

Error C2440: 'initializing' : cannot convert from 'std::map<_Kty,_Ty>' to 'JsonValue'

此外,如何将JsonValue安全地转换为JsonObject?当我尝试做:

boost::get<JsonObject>(aval) = JsonObject();

这会导致运行时异常/致命故障。

非常感谢您的帮助。

编辑:

根据@Nicol的建议,我得出了以下代码:

struct JsonNull {};
struct JsonValue;
typedef std::map<std::string, JsonValue *> JsonObject;
typedef std::vector<JsonValue *> JsonArray;
typedef boost::variant<
    JsonNull, bool, long, double, std::string,
    JsonObject, JsonArray,
    boost::recursive_wrapper<JsonValue>
> JsonDataValue;
struct JsonValue
{
    JsonDataValue data;
};

我可以在JsonObject&JsonArray就这么简单:

JsonValue *pJsonVal = new JsonValue();
boost::get<JsonObject>(pCurrVal->data).insert(
    std::pair<std::string, JsonValue *>("key", pJsonVal)
);
boost::get<JsonArray>(pCurrVal->data).push_back(pJsonVal);

只是为了让每个人都能从中受益。

您必须使用递归包装器(并且不应该从boost::variant派生(:

struct JsonValue;
typedef boost::variant</*types*/, boost::recursive_wrapper<JsonValue> > JsonDataValue;
struct JsonValue
{
    JsonDataValue value;
};

要使BoostSpirit获得JsonValue,您需要编写其中一个Fusion适配器,以将原始变体类型调整为结构。


此外,如何将JsonValue安全地转换为JsonObject?当我尝试做:

变体不是这样工作的。如果你想将它们设置为一个值,只需像设置其他值一样设置它们:

JsonValue val;
val.value = JsonValue();