0

While trying parsing a json string in my c++ code, using the library minijson, I got a code like that so far:

    <<"version">> [&]() { result.setVersion(v.as_long()); }
    <<"capabilities">> [&]()
    {
        parse_array(ctx, [&](value capability)
        {
            result.getCapabilities().push_back(capability.as_string());
        });
    }

the data should be stored on this struct:

struct block_template {
  int version;
  vector<string> capabilities;
  ...
}

the version value is stored correctly, but the vector is staying with size 0. I try visualize the data being read from the json string ( with cout << capability.as_string() << endl ) and it's display correctly, just not being stored in the data structure.

Anyone who already worked with this library can give a hint of what's wrong here?

Kleber Mota
  • 8,521
  • 31
  • 94
  • 188
  • I have not seen this: `<<"version">>` before. Is this a new part of C++ or part of `minijson? – Martin York Jun 24 '20 at 22:02
  • @MartinYork It is probably some heavy abuse of `operator<<` and `operator>>` by `minijson`. I assume op has omitted some code like `parser <<"version">>...` – Sebastian Hoffmann Jun 24 '20 at 22:59
  • For what youre trying to achieve OP: Im personally very happy with a combination of `simdjson` with `boost hana`. simdjson for fast parsing with a suprinsingly nice interface and boost hana for its `Struct` concept which allows one to get some compile-time reflection on c++ types. – Sebastian Hoffmann Jun 24 '20 at 23:02
  • I like ThorsSerializer (but I wrote it so may be biased). – Martin York Jun 24 '20 at 23:56
  • @SebastianHoffmann Can I get a simple example using both this libraries? I found the github page for both projects, but there I only got code example for individual use of them. – Kleber Mota Jun 25 '20 at 10:26
  • @KleberMota You basically need an overload for each datatype you want to support (e.g `std::vector`, `double`, etc). The most important overload is a template function taking in any `boost::hana::Struct` (you'll have to use `std::enable_if` here or a similiar SFINAE technique). This overload will iterate over each member (using `hana::for_each`) and recursively call the conversion function again. See https://www.boost.org/doc/libs/1_61_0/libs/hana/doc/html/index.html#tutorial-introspection-adapting for what i mean. – Sebastian Hoffmann Jun 25 '20 at 11:51

1 Answers1

1

Since the OP asks for examples using other libraries in the comments, I'll reply more generally.

In jsoncons, if the JSON member names and the C++ variable names were the same, you could use the macro JSONCONS_ALL_MEMBER_TRAITS to set up the mappings,

#include <iostream>
#include <jsoncons/json.hpp>

struct block_template {
  int version;
  std::vector<std::string> capabilities;
};

JSONCONS_ALL_MEMBER_TRAITS(block_template, version, capabilities)

int main()
{
    std::string input = R"(
    {
        "version" : 1,
        "capabilities" : ["foo","bar","baz"]
    }
    )";

    auto result = jsoncons::decode_json<block_template>(input);

    std::cout << "(1)\n" << "version: " << val.version << "\n";
    for (auto& item : val.capabilities)
    {
        std::cout << "item: " << item << "\n";
    }

    std::string output;
    jsoncons::encode_json(val, output, jsoncons::indenting::indent);
    std::cout << "(2)\n" << output << "\n\n";
}

Output:

(1)
version: 1
item: foo
item: bar
item: baz
(2)
{
    "capabilities": ["foo", "bar", "baz"],
    "version": 1
}

And if the JSON and C++ names were different, you could use the macro JSONCONS_ALL_MEMBER_NAME_TRAITS instead,

JSONCONS_ALL_MEMBER_NAME_TRAITS(block_template, (version,"Version"), 
                                (capabilities,"Capabilities"))

With this change, the output becomes:

(1)
version: 1
item: foo
item: bar
item: baz
(2)
{
    "Capabilities": ["foo", "bar", "baz"],
    "Version": 1
}

See this answer for more examples of libraries that decode JSON to C++ data structures and encode back again, including Martin York's interesting ThorsSerializer.

Daniel
  • 728
  • 7
  • 11