c++jsonnlohmann-json

Read json data into structure which has explicit constructor C++


I have a structure which has an explicit constructor -

struct structA {
    explicit structA(const std::size_t num) : a(num) {}
    std::vector<structB> a;
    glm::quat b;
    glm::vec3 c;
    glm::vec3 d{1.0f};
};

I have a to_json and from_json for structA as below -

inline void to_json(json& j, const structA& t) {
    j = {{"a", t.a},
         {"b", t.b},
         {"c", t.c},
         {"d", t.d}};
}

inline void from_json(const json& j, structA& t) {
    j.at("a").get_to(t.a);
    j.at("b").get_to(t.b);
    j.at("c").get_to(t.c);
    j.at("d").get_to(t.d);
} 

to_json() works fine and the json file is filled properly.

note - I have to and from json for structB as well and structB doesnt have an exlipcit constructor and is working as expected

When I try to read the structA values from the json as below, I pass in the value 21 as arg since the explicit constructor needs an input value.

const auto& structAVal = frameJson["structA"].get<structA>(21);

But I get a compile error as -

include/nlohmann_json/nlohmann/json.hpp:19336:16: note: candidate function template not viable: requires 0 arguments, but 1 was provided 
basic_json get() const

include/nlohmann_json/nlohmann/json.hpp:19336:16: note: candidate function template not viable: requires 0 arguments, but 1 was provided 
 BasicJsonType get() const

include/nlohmann_json/nlohmann/json.hpp:19336:16: note: candidate function template not viable: requires 0 arguments, but 1 was provided 
ValueType get() const noexcept(noexcept(

Question - Where am I going wrong here ? The error above looks like from_json() needs another input arg ??

If I dont provide the input arg 21 in the constructor arg while reading the json, I get a bunch of errors on the lines of

1 argument expected, 0 provided

So it is a cyclic loop


Solution

  • https://github.com/nlohmann/json#basic-usage

    "When using template get<your_type>(), your_type MUST be DefaultConstructible. (There is a way to bypass this requirement described later.)"

    https://github.com/nlohmann/json#how-can-i-use-get-for-non-default-constructiblenon-copyable-types

    There is a way, if your type is MoveConstructible. You will need to specialize the adl_serializer as well, but with a special from_json overload:

    So I think your answer lies in this idea. (Following code untested and probably doesn't compile)

    namespace nlohmann {
        template <>
        struct adl_serializer< structA> {
            // note: the return type is no longer 'void', and the method only takes
            // one argument
            static structA from_json(const json& j) {
                std::size_t num;
                j.at("a").get_to(num);
                structA t{a};
                j.at("b").get_to(t.b);
                j.at("c").get_to(t.c);
                j.at("d").get_to(t.d);
                return t;
            }
    
            // Here's the catch! You must provide a to_json method! Otherwise, you
            // will not be able to convert move_only_type to json, since you fully
            // specialized adl_serializer on that type
            static void to_json(json& j, structA t) {
                j = {{"a", t.a},
                     {"b", t.b},
                     {"c", t.c},
                     {"d", t.d}};
            }
        };
    }