Json: to_json for pairs, tuples

Created on 10 Jun 2017  路  14Comments  路  Source: nlohmann/json

Hi, I was wondering if there might be a simple way to to_json() pairs and tuples, instead of having to explicitly create each element for json.

question proposed fix

All 14 comments

I'm not sure what you mean. Could you provide more details or an example please?

Thanks for the reply! For example, let's say i want to encode an std::pair into json.
Ideally:

struct Person
{
    std::pair<int, int> position
};
    void to_json( json& j, const Person& d )
    {
        j = json{
            { "position", d.position }
        };
    }
    void from_json( const json& j, Person& d )
    {
        d.position= j.at( "position" ).get<std::pair<int, int>>();
    }

But sadly this gives an error.
Instead, I have to encode each element of the pair (or tuple) explicitly as a different json element, which can get slightly troublesome.

Hopefully I've just misunderstood something and there is a direct method, otherwise it would be absolutely great to be able to do this.

Have you tried something like this? (I'm not sure if it will work, just speculating)

void to_json( json& j, const Person& d )
{
    to_json(j["position"], d.position);
}
void from_json( const json& j, lvn::NTextbox::NChar::Data& d )
{
    from_json(j["position"], d.position);
}

There is no default conversion between json and std::pair. You need to provide translations from/to arrays. This would work:

#include "json.hpp"

using json = nlohmann::json;

struct Person
{
    std::pair<int, int> position;
};

void to_json( json& j, const Person& d )
{
    // encode pair as a list
    j = json{ { "position", {d.position.first, d.position.second} } };
}

void from_json( const json& j, Person& d )
{
    auto& pos = j.at("position");
    // decode list as pair
    d.position = std::make_pair(pos[0], pos[1]);
}

int main()
{
    // create a person
    Person p;
    p.position = {17, 42};

    // person -> json
    json j = p;
    std::cout << std::setw(2) << j << std::endl;

    // json -> person
    Person p2 = j;
    std::cout << std::boolalpha << (p.position == p2.position) << std::endl;
}

I added support for std::pair in a recent PR, however it requires the .first to be a compatible string type , so it can represent the combination of a string field, and a JSON object.

I didn't think about representing pairs as arrays (e.g. std::pair<int, int>), this should be discussed, and we might need to revert my PR.

In my own codebase, I have a function that encodes them as an object withfirst and second members.

I think encoding pairs and tuples as JSON arrays could be a good idea. However, I am not sure about std::pair<std::string, X> in this context. I think a single pair should not be encoded as JSON object.

Since almost any to_json method provided by the library can be overwritten, we could provide a reasonable default for std::pair.

Fixing #600 while staying generic-friendly in the implementation of to_json(CompatibleObjectType) is quite hard, especially if we need to rely on CompatibleObjectType::value_type...

I don't really know what to do with this std::pair problem

I think you're right, we should convert pairs and tuples as arrays, element ordering being mandatory for those.

People with custom conversions with std::pair (like @gregmarr) won't be impacted by this change anyway.

Exactly. I wanted to write the same. I think it is a good and predictable behavior to use arrays.

Ok, I have (finally) some time to work on the library, I'm starting to implement this. I will then try to extract some nested classes as we discussed in #474.

Great. #458 shows some challenges when it comes to parsing. Some restructuring of the code may help here.

I wouldn't be affected anyway, as my functions were written before to_json and from_json were added to the library and thus are completely outside the library.

With #624, the library now also supports the conversion from/to std::pair, std::tuple, and std::array.

Was this page helpful?
0 / 5 - 0 ratings