Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

push_back doesn't work for serializing containers #3027

Closed
CrackerHax opened this issue Sep 22, 2021 · 8 comments
Closed

push_back doesn't work for serializing containers #3027

CrackerHax opened this issue Sep 22, 2021 · 8 comments

Comments

@CrackerHax
Copy link

CrackerHax commented Sep 22, 2021

This is probably more of a feature request than a bug, but would be really great if it could behave like an arbitrary container.

struct foobar
{
  std::string foo;                                                                                                                            
  std::string bar;                                                                                                                        
};

void to_json(json& j, const foobar& p)
{
  j = json {
            {"foo", p.foo },
            {"bar", p.bar }
  };
};

void from_json(const json& j, foobar& p)
{
  j.at("foo").get_to( p.foo );
  j.at("bar").get_to( p.bar );
};

json j;
foobar f("foostr", "barstr");

j.push_back(f);
j.push_back(foobar("foostr2", "barstr2"));
j.erase(f);

error: no matching function for call to ‘nlohmann::basic_json<>::push_back(foobar&)’

@CrackerHax CrackerHax changed the title push_back doesn't not work for serialized STL containers push_back doesn't not work for serializing Sep 22, 2021
@CrackerHax CrackerHax changed the title push_back doesn't not work for serializing push_back doesn't work for serializing Sep 22, 2021
@CrackerHax CrackerHax changed the title push_back doesn't work for serializing push_back doesn't work for serializing containers Sep 22, 2021
@gregmarr
Copy link
Contributor

That works just fine, except for the j.erase(f) and that you don't have a constructor for foobar, though changing from foobar() to foobar{} works for that.

https://godbolt.org/z/1vc7nE1fa

@gregmarr
Copy link
Contributor

The j.erase(f); doesn't work for std::vector<foobar> either, and that's basically what j is emulating here.

@CrackerHax
Copy link
Author

CrackerHax commented Sep 22, 2021

Actually it doesnt work. The only way I could get this to work is to create a container for the containers like so:


struct foobars
{
    std::vector<foobar> f;
}

then the to_json, and from_json ..

Also, according to documentation erase should work too.

// delete an entry
o.erase("foo");

@CrackerHax
Copy link
Author

I am using this for storing redis entries, so it reads and writes to/from json strings. I would like a way to read the string into a json object and push_back or erase without having to parse it back into the struct object first.

@gregmarr
Copy link
Contributor

Did you look at the link I included? That shows it compiling. Is there something in your code that you didn't include in your sample that makes it not work?

Also, according to documentation erase should work too.

// delete an entry
o.erase("foo");

That's for an object, this is an array.

I am using this for storing redis entries, so it reads and writes to/from json strings. I would like a way to read the string into a json object and push_back or erase without having to parse it back into the struct object first.

The push_back function is for arrays. Sounds like you want an object instead.

j["key"] = json::parse(string).
j.erase("key");

@CrackerHax
Copy link
Author

CrackerHax commented Sep 23, 2021

Sounds like you want an object instead.

Yes, I want push_back for objects. Sorry I guess I didn't explain myself very well.
The json would look something like this:

{
   { "foo": "foostr", "bar":"barstr"}
}

@gregmarr
Copy link
Contributor

That's not a valid json. You can't have an object as top level inside an object like that.

You can have an array of objects:

[
   { "foo": "foostr", "bar":"barstr"}
]

You can have just an object:

{ "foo": "foostr", "bar":"barstr"}

Or you can have a nested object:

{
   "baz": { "foo": "foostr", "bar":"barstr"}
}

The formats of push_back and += that work when j is an object look like this "add these members to the object j."

void to_json(json& j, const foobar& p)
{
    j.push_back(json::object_t::value_type{"foo", p.foo });
    j.push_back({"bar", p.bar });
    j += json::object_t::value_type{"foo", p.foo };
    j += {"bar", p.bar };
};

For normal nlohmann::json, aka nlohmann::basic_json<>, json::object_t::value_type is std::map<std::string, json>::value_type which is std::pair<const std::string, json>.

@nlohmann
Copy link
Owner

Is there anything to be done here?

@nlohmann nlohmann closed this as completed Oct 7, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants