Reputation: 76756
I'm working a small C++ JSON library to help sharpen my rusty C++ skills, and I'm having trouble understanding some behavior with initialization lists.
The core of the library is a variant class (named "var") that stores any of the various JSON datatypes (null, boolean, number, string, object, array).
The goal is for var
to work as closely as possible to a JavaScript variable, so there's lots of operator overloading going on. The primitive datatypes are easy to take care of...
var fee = "something";
var fie = 123.45;
var foe = false;
The problem is with objects (maps) and arrays (vectors).
To get something close to a JavaScript object and array literal syntax, I'm using initialization lists. It looks like this:
// in my headers
typedef var object[][2];
typedef var array[];
// in user code
var foo = (array){ 1, "b", true };
var bar = (object){ { "name", "Bob" }, { "age", 42 } };
This works out pretty nicely. The problem comes in with nested lists.
var foo = (array){ 1, "b", (array){ 3.1, 3.2 } };
For some reason my variant class interprets the nested "array" as a boolean, giving:
[1, "b", true]
Instead of:
[1, "b", [3.1, 3.2]]
If I explicitly cast the inner list to a var, it works:
var foo = (array){ 1, "b", (var)(array){ 3.1, 3.2 } };
Why do I have to explicitly cast the inner list to a var after I cast it to an array, and how can I get around this extra cast? As far as I can tell it should be implicitly converting the array to my var class anyway, since it's using the constructor for an array of vars:
template <size_t length>
var(const var(&start)[length]) {
// internal stuff
init();
setFromArray(vector<var>(start, start + length));
}
It seems that without the explicit cast to var, the initialization list somehow gets cast to something else on its way from being cast from an array to a var. I'm trying to understand why this happens, and how to avoid it.
Here's a gist with the complete source. Let me know if I should add anything relevant to the question.
Update
Apparently (foo){1, "two"}
does not actually cast an initialiation list; it's a complete expression called a compound literal. It seems that it's only available in C, although g++ doesn't complain unless you give it -pedantic
.
It looks like my options are:
Any help with the first option would be the sort of answer I'm looking for at this point.
Macros are another sort of last-ditch option, and I've written some that do the job, but I'd like to not have to use them.
Upvotes: 2
Views: 1489
Reputation: 146968
You need to use the facilities already provided to you by Boost.
typedef boost::optional<boost::make_recursive_variant<
float, int, bool, //.. etc
std::unordered_map<std::string, boost::optional<boost::recursive_variant_>>,
std::vector<boost::recursive_variant_>
> JSONType;
They can easily define recursive variant types.
Upvotes: 1