7

I'm trying to parse JSON string using Boost Spirit store JSON object into recursive data structures:

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

And here's my code:

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

When compiling I get the error:

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

Moreover, how to safely cast JsonValue to JsonObject? When I try doing:

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

This gets run-time exception/fatal failure.

Any help is greatly appreciated.

EDIT:

Following @Nicol's advice, I came out with the following code:

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

I can work on JsonObject & JsonArray as easy as this:

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

Just posting so that everyone could benefit from this.

Viet
  • 17,944
  • 33
  • 103
  • 135

1 Answers1

6

You have to use a recursive wrapper (and you shouldn't be deriving from boost::variant):

struct JsonValue;

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

struct JsonValue
{
    JsonDataValue value;
};

To make Boost.Spirit take a JsonValue, you will need to write one of those Fusion adaptor things to adapt the raw variant type into a struct.


Moreover, how to safely cast JsonValue to JsonObject? When I try doing:

That's not how variants work. If you want to set them to a value, just set them like any other value:

JsonValue val;
val.value = JsonValue();
Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • Thanks Nicol for prompt answer! I have the JsonArray and JsonObject types as you see, how could I make use of them when following your path? Could you please discuss in greater detail? Thank you! – Viet Jul 03 '11 at 07:48
  • @Protege: Like most parts of Boost, [Variant](http://www.boost.org/doc/libs/1_46_1/doc/html/variant/tutorial.html) has very good documentation. You should read it. It will save both of us a lot of time. – Nicol Bolas Jul 03 '11 at 07:51
  • I read many times on Variant but couldn't comprehend. I was trying to plug std::map and std::vector into JsonValue. Thanks anyway. – Viet Jul 03 '11 at 07:54
  • Chill, I found the answer! Thanks for your hint! – Viet Jul 03 '11 at 11:38