Why you avoid answering from where you got the
wordage that you used? My source is every
specification that I have read. Whatever language
or interface that supports JSON uses Name (not
Key), String (not Str) and Number (not Numeric).
Look at
json.org it also uses those:
https://www.json.org/
It is difficult to discuss stuff when terminology is
pointlessly skewed by some part.
> > Looking at your code "object" seems missing. Why?
> > Usually when receiving JSON then it is UTF-8 file
> > consisting of one, root object. I would expect it
> > to be something like:
>
> At least at the moment, Object is represented by:
>
> using object_t = std::vector<boost::tuple<key_t, value_t>>;
Ok. It wasn't when I looked at your code.
> The awkward part is that value_t needs to be a fully declared type at the moment Boost.Variant finds it in the template specialization. I have, however, taken to declaring the type alias immediately thereafter so that at least subscribers to value_t see it as the expected object_t.
Yes, the whole idea of JSON is deeply recursive.
That means we have to use another layer of
indirection at spots of breaking the recursion.
With boost::variant there is possibility to make
recursive variants. Unfortunately these are tricky
to make compile on some compilers and then
heap-allocate under the hood.
I would instead go with std::variant and
std::unique_ptr to not fully defined types at
spots of breaking recursion. It is simple enough to
use first at spots chosen by "best readability".
Later the spots are easier to change and also
management of owned object of unique_ptr is
simpler to customize for to optimize. That "later"
in sense that it is performance optimization ... for
time when the thing works and so there is point
to optimize it at all.
I am in doubt about Boost.Spirit ... IOW why it?
When I tried it then it compiled awkwardly slowly
and the compiling diagnostics were horrible when
it failed to compile. Parse-time error handling was
quite inconvenient to hook into it. Resulting parser
performed about 3 times worse than equivalent
parser made by other parser generator. That all
made it feel like lose-lose-lose choice. It was
about 4 or 5 years ago, maybe spirit has improved
in some aspects since then but I doubt it.
>
> > using object = std::unordered set<name,value>;
>
> It's an excellent point in and of itself. I was unaware of Unordered Set, per se; that would be preferable, I think; it would certainly be more concise than Vector of Member Tuples. The main issue there would be whether I could synthesize its elements or otherwise emplace them during parsing. As others mentioned, yes, more of a question for Boost and/or Boost.Spirit forums.
Hmm. Yes, My mistake ... actually it should be
unordered_map<name, value>. Its interface is
most convenient. For example value v to name n
in object o can be set just with "o[n] = v;".
The o[n] returns reference to value or default-
constructed value when it didn't exist.
It is likely that vector of pairs is performing better
when objects have only few members and
unorded_map is better when objects have lot of
members but making such choices or using
both (as variants) is again about performance,
so leave for later. Choose by convenience of
interface for task first and only when all tests
run then tinker with performance.