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

From Version 2.1.1 to 3.6.1 serialize std::set #1676

Closed
MattiasEppler opened this issue Jul 19, 2019 · 5 comments
Closed

From Version 2.1.1 to 3.6.1 serialize std::set #1676

MattiasEppler opened this issue Jul 19, 2019 · 5 comments

Comments

@MattiasEppler
Copy link

MattiasEppler commented Jul 19, 2019

I upgraded to version 3.6.1 until this I serialized a std::set in this way


class Settings
{
  std::set<MetaData> Clients{};
}

inline void to_json(json& j, const Settings& settings)
{
        j = json
        {
            { "clients", settings.Clients },
        };
}

inline void from_json(const json& j, Settings& settings)
{
        auto clients = j.at("clients").get<vector<MetaData>>();

        for (const auto& client : clients)
        {
            settings.Clients.insert(client);
        }
}

Now I get the errors:

Error C2440: 'initializing': cannot convert from 'initializer list' to 'nlohmann::json' (142)
Error C2672: 'nlohmann::basic_jsonstd::map,std::vector,std::string,bool,int64_t,uint64_t,double,std::allocator,nlohmann::adl_serializer::get': no matching overloaded function found (160)

@MattiasEppler MattiasEppler changed the title From Version 2.1.1 to 3.6.1 serialize vector From Version 2.1.1 to 3.6.1 serialize std::set Jul 19, 2019
@MattiasEppler
Copy link
Author

It is not only the std::set. Its a problem with serialiize std containers.
I switched my project back to 3.0.1.
The code above is working in this version. So we can change the label from question to bug.

@nlohmann
Copy link
Owner

The example is incomplete (there is code missing, and there are syntax errors). Could you please provide a small example that does compile with 2.1.1?

@MattiasEppler
Copy link
Author

MattiasEppler commented Jul 22, 2019

Sorry. Complete example:
The enum is commented out. So the example works in 3.0.1.

#include "json.hpp"
#include <set>
#include <iostream>

using nlohmann::json;
using namespace std;

namespace pdx
{
    using nlohmann::json;
    using namespace std;

    //enum class CyclicErrorAction
    //{
    //    None,
    //    Stop,
    //    StopAll
    //};

    //
    //NLOHMANN_JSON_SERIALIZE_ENUM( CyclicErrorAction, 
    //{
    //    { CyclicErrorAction::None, "None"},
    //    { CyclicErrorAction::Stop, "Stop"},
    //    { CyclicErrorAction::StopAll, "StopAll"},  
    //})

    class MetaData
    {
    public:

        string Name;
    };


    class Settings
    {
            
    public:

        //CyclicErrorAction OnCyclicError = CyclicErrorAction::None;
        
        bool ShowAdditionalTrace = false;
        std::string Source;
        std::set<MetaData> Clients{};

        
    };
        
    inline void to_json(json& j, const Settings& settings)
    {
        j = json
        {
            //{ "onCyclicError", settings.OnCyclicError },
            { "showAdditionalTrace", settings.ShowAdditionalTrace },
            { "clients", settings.Clients },
            { "source", settings.Source },
            
        };
    }

    inline void from_json(const json& j, Settings& settings)
    {
        //settings.OnCyclicError = j.at("onCyclicError").get<decltype(settings.OnCyclicError)>();
        settings.ShowAdditionalTrace = j.at("showAdditionalTrace").get<decltype(settings.ShowAdditionalTrace)>();
        settings.Source = j.at("source").get<decltype(settings.Source)>();
        
        auto clients = j.at("clients").get<std::vector<MetaData>>();

        for (const auto& client : clients)
        {
            settings.Clients.insert(client);
        }
    }

    inline void to_json(json& j, const MetaData& metaData)
    {
        j["name"] = metaData.Name;

    }

    inline void from_json(const json& j, MetaData& metaData)
    {
        metaData.Name = j.at("name").get<decltype(metaData.Name)>();
    }
}

using namespace pdx;

int main()
{
    std::cout << "Start!\n";

    Settings settings {};

    const auto j = json(settings);

    const auto s =  j.get<Settings>();
}

@nlohmann
Copy link
Owner

This code compiles with Xcode 10.3 with the develop version. I had to make two changes:

  1. Move the from_json/to_json methods for MetaData up above their first use in the from_json method for Settings.
  2. Add a comparison operator for MetaData to use it in a std::set.

I am not sure why this code would have compiled in earlier versions.

#include "json.hpp"

#include <set>
#include <iostream>

using nlohmann::json;
using namespace std;

namespace pdx
{
    using nlohmann::json;
    using namespace std;
    
    //enum class CyclicErrorAction
    //{
    //    None,
    //    Stop,
    //    StopAll
    //};
    
    //
    //NLOHMANN_JSON_SERIALIZE_ENUM( CyclicErrorAction,
    //{
    //    { CyclicErrorAction::None, "None"},
    //    { CyclicErrorAction::Stop, "Stop"},
    //    { CyclicErrorAction::StopAll, "StopAll"},
    //})
    
    class MetaData
    {
    public:
        string Name;
        friend bool operator<(const MetaData& a, const MetaData& b) { return a.Name < b.Name; }
    };
    
    inline void to_json(json& j, const MetaData& metaData)
    {
        j["name"] = metaData.Name;
        
    }
    
    inline void from_json(const json& j, MetaData& metaData)
    {
        metaData.Name = j.at("name").get<decltype(metaData.Name)>();
    }

    class Settings
    {
        
    public:
        
        //CyclicErrorAction OnCyclicError = CyclicErrorAction::None;
        
        bool ShowAdditionalTrace = false;
        std::string Source;
        std::set<MetaData> Clients{};
        
        
    };
    
    inline void to_json(json& j, const Settings& settings)
    {
        j = json
        {
            //{ "onCyclicError", settings.OnCyclicError },
            { "showAdditionalTrace", settings.ShowAdditionalTrace },
            { "clients", settings.Clients },
            { "source", settings.Source },
            
        };
    }
    
    inline void from_json(const json& j, Settings& settings)
    {
        //settings.OnCyclicError = j.at("onCyclicError").get<decltype(settings.OnCyclicError)>();
        settings.ShowAdditionalTrace = j.at("showAdditionalTrace").get<decltype(settings.ShowAdditionalTrace)>();
        settings.Source = j.at("source").get<decltype(settings.Source)>();
        
        auto clients = j.at("clients").get<std::vector<MetaData>>();
        
        for (const auto& client : clients)
        {
            settings.Clients.insert(client);
        }
    }
}

using namespace pdx;

int main()
{
    std::cout << "Start!\n";
    
    Settings settings {};
    
    const auto j = json(settings);
    
    const auto s =  j.get<Settings>();
}

@MattiasEppler
Copy link
Author

Hi, oh so the order was the only problem. 😢
The operator < is implemented in my real project. I just removed it in my sample for simplicity. In 2.1.1 it was working without the operator.

Thanks for your quick help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants