Вариант Boost: как моделировать JSON?

Я пытаюсь разобрать строку JSON, используя объект JSON хранилища Boost Spirit, в рекурсивные структуры данных:

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);

Просто публикую, чтобы каждый мог извлечь из этого пользу.


person Viet    schedule 03.07.2011    source источник


Ответы (1)


Вы должны использовать рекурсивную оболочку (и вы не должны быть производными от boost::variant):

struct JsonValue;

typedef boost::variant</*types*/, boost::recursive_wrapper<JsonValue> > JsonDataValue;

struct JsonValue
{
    JsonDataValue value;
};

Чтобы заставить Boost.Spirit принимать JsonValue, вам нужно будет написать одну из этих вещей адаптера Fusion, чтобы адаптировать необработанный тип варианта в структуру.


Более того, как безопасно преобразовать JsonValue в JsonObject? Когда я пытаюсь сделать:

Это не то, как работают варианты. Если вы хотите установить для них значение, просто установите их как любое другое значение:

JsonValue val;
val.value = JsonValue();
person Nicol Bolas    schedule 03.07.2011
comment
Спасибо Николь за оперативный ответ! У меня есть типы JsonArray и JsonObject, как вы видите, как я могу использовать их, следуя вашему пути? Не могли бы вы обсудить более подробно? Благодарю вас! - person Viet; 03.07.2011
comment
@Protege: Как и большинство частей Boost, Variant имеет очень хорошую документацию. Вы должны прочитать это. Это сэкономит нам обоим много времени. - person Nicol Bolas; 03.07.2011
comment
Я много раз читал Вариант, но не мог понять. Я пытался подключить std::map и std::vector к JsonValue. Спасибо, в любом случае. - person Viet; 03.07.2011
comment
Успокойтесь, я нашел ответ! Спасибо за подсказку! - person Viet; 03.07.2011