Json: Newbie issue: how does one convert a map in Json back to std::map?

Created on 1 Jun 2017  Â·  26Comments  Â·  Source: nlohmann/json

I have a map..

j["rightHand"] = std::map<std::string, std::string> {{ 
                    some_string, 
                    some_other_string }};

But when I go to retrieve the map I get an 'call of overload is ambiguous' type error:

        const json& rh = j["rightHand"]; 
       std::map<std::string, std::string> rightHand  = rh;

Could you perhaps point me to where I can find an example of how to do this properly? I've searched but can't seem to find anything directly on point

Thanks!

question

Most helpful comment

I'm glad it wasn't me being a total newbie. It seemed like I was using valid syntax.

All 26 comments

I assume j is of type nlohmann::json?

Correct

Interestingly, the issue is if the value is a std::string.

This works:

#include "json.hpp"

using json = nlohmann::json;

int main()
{
    // create a map
    std::map<std::string, int> m1 {{"key", 1}};

    // create and print a JSON from the map
    json j = m1;
    std::cout << j << std::endl;

    // get the map out of JSON
    std::map<std::string, int> m2 = j;

    // make sure the roundtrip succeeds
    assert(m1 == m2);
}

This does not:

#include "json.hpp"

using json = nlohmann::json;

int main()
{
    // create a map
    std::map<std::string, std::string> m1 {{"key", "val"}};

    // create and print a JSON from the map
    json j = m1;
    std::cout << j << std::endl;

    // get the map out of JSON
    std::map<std::string, std::string> m2 = j;

    // make sure the roundtrip succeeds
    assert(m1 == m2);
}

Error message:

In file included from foo.cpp:1:
In file included from src/json.hpp:32:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/algorithm:627:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/utility:284:33: error: 
      call to constructor of 'std::__1::basic_string<char>' is ambiguous
            : first(__p.first), second(__p.second) {}
                                ^      ~~~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/memory:1752:31: note: 
      in instantiation of function template specialization 'std::__1::pair<const
      std::__1::basic_string<char>, std::__1::basic_string<char> >::pair<const
      std::__1::basic_string<char>, nlohmann::basic_json<std::map, std::vector,
      std::__1::basic_string<char>, bool, long long, unsigned long long, double,
      std::allocator, adl_serializer> >' requested here
            ::new((void*)__p) _Up(_VSTD::forward<_Args>(__args)...);
                              ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/memory:1668:18: note: 
      in instantiation of function template specialization
      'std::__1::allocator<std::__1::__tree_node<std::__1::__value_type<std::__1::basic_string<char>,
      std::__1::basic_string<char> >, void *> >::construct<std::__1::pair<const
      std::__1::basic_string<char>, std::__1::basic_string<char> >, const
      std::__1::pair<const std::__1::basic_string<char>,
      nlohmann::basic_json<std::map, std::vector, std::__1::basic_string<char>,
      bool, long long, unsigned long long, double, std::allocator,
      adl_serializer> > &>' requested here
            {__a.construct(__p, _VSTD::forward<_Args>(__args)...);}
                 ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/memory:1514:14: note: 
      in instantiation of function template specialization
      'std::__1::allocator_traits<std::__1::allocator<std::__1::__tree_node<std::__1::__value_type<std::__1::basic_string<char>,
      std::__1::basic_string<char> >, void *> >
      >::__construct<std::__1::pair<const std::__1::basic_string<char>,
      std::__1::basic_string<char> >, const std::__1::pair<const
      std::__1::basic_string<char>, nlohmann::basic_json<std::map, std::vector,
      std::__1::basic_string<char>, bool, long long, unsigned long long, double,
      std::allocator, adl_serializer> > &>' requested here
            {__construct(__has_construct<allocator_type, _Tp*, _Args...>(),
             ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__tree:2152:20: note: 
      in instantiation of function template specialization
      'std::__1::allocator_traits<std::__1::allocator<std::__1::__tree_node<std::__1::__value_type<std::__1::basic_string<char>,
      std::__1::basic_string<char> >, void *> >
      >::construct<std::__1::pair<const std::__1::basic_string<char>,
      std::__1::basic_string<char> >, const std::__1::pair<const
      std::__1::basic_string<char>, nlohmann::basic_json<std::map, std::vector,
      std::__1::basic_string<char>, bool, long long, unsigned long long, double,
      std::allocator, adl_serializer> > &>' requested here
    __node_traits::construct(__na, _NodeTypes::__get_ptr(__h->__value_)...
                   ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__tree:2130:29: note: 
      in instantiation of function template specialization
      'std::__1::__tree<std::__1::__value_type<std::__1::basic_string<char>,
      std::__1::basic_string<char> >,
      std::__1::__map_value_compare<std::__1::basic_string<char>,
      std::__1::__value_type<std::__1::basic_string<char>,
      std::__1::basic_string<char> >,
      std::__1::less<std::__1::basic_string<char> >, true>,
      std::__1::allocator<std::__1::__value_type<std::__1::basic_string<char>,
      std::__1::basic_string<char> > > >::__construct_node<const
      std::__1::pair<const std::__1::basic_string<char>,
      nlohmann::basic_json<std::map, std::vector, std::__1::basic_string<char>,
      bool, long long, unsigned long long, double, std::allocator,
      adl_serializer> > &>' requested here
        __node_holder __h = __construct_node(_VSTD::forward<_Args>(__args)...);
                            ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__tree:1230:14: note: 
      (skipping 8 contexts in backtrace; use -ftemplate-backtrace-limit=0 to see
      all)
      return __emplace_hint_unique_key_args(__p, __x.first, _VSTD::forwa...
             ^
src/json.hpp:1138:16: note: in instantiation of function template specialization
      'nlohmann::detail::from_json_fn::call<nlohmann::basic_json<std::map,
      std::vector, std::__1::basic_string<char>, bool, long long, unsigned long
      long, double, std::allocator, adl_serializer>,
      std::__1::map<std::__1::basic_string<char>, std::__1::basic_string<char>,
      std::__1::less<std::__1::basic_string<char> >,
      std::__1::allocator<std::__1::pair<const std::__1::basic_string<char>,
      std::__1::basic_string<char> > > > >' requested here
        return call(j, val, priority_tag<1> {});
               ^
src/json.hpp:1185:9: note: in instantiation of function template specialization
      'nlohmann::detail::from_json_fn::operator()<nlohmann::basic_json<std::map,
      std::vector, std::__1::basic_string<char>, bool, long long, unsigned long
      long, double, std::allocator, adl_serializer>,
      std::__1::map<std::__1::basic_string<char>, std::__1::basic_string<char>,
      std::__1::less<std::__1::basic_string<char> >,
      std::__1::allocator<std::__1::pair<const std::__1::basic_string<char>,
      std::__1::basic_string<char> > > > >' requested here
        ::nlohmann::from_json(std::forward<BasicJsonType>(j), val);
        ^
src/json.hpp:3490:36: note: in instantiation of function template specialization
      'nlohmann::adl_serializer<std::__1::map<std::__1::basic_string<char>,
      std::__1::basic_string<char>, std::__1::less<std::__1::basic_string<char>
      >, std::__1::allocator<std::__1::pair<const std::__1::basic_string<char>,
      std::__1::basic_string<char> > > >, void>::from_json<const
      nlohmann::basic_json<std::map, std::vector, std::__1::basic_string<char>,
      bool, long long, unsigned long long, double, std::allocator,
      adl_serializer> &, std::__1::map<std::__1::basic_string<char>,
      std::__1::basic_string<char>, std::__1::less<std::__1::basic_string<char>
      >, std::__1::allocator<std::__1::pair<const std::__1::basic_string<char>,
      std::__1::basic_string<char> > > > >' requested here
        JSONSerializer<ValueType>::from_json(*this, ret);
                                   ^
src/json.hpp:3752:16: note: in instantiation of function template specialization
      'nlohmann::basic_json<std::map, std::vector, std::__1::basic_string<char>,
      bool, long long, unsigned long long, double, std::allocator,
      adl_serializer>::get<std::__1::map<std::__1::basic_string<char>,
      std::__1::basic_string<char>, std::__1::less<std::__1::basic_string<char>
      >, std::__1::allocator<std::__1::pair<const std::__1::basic_string<char>,
      std::__1::basic_string<char> > > >,
      std::__1::map<std::__1::basic_string<char>, std::__1::basic_string<char>,
      std::__1::less<std::__1::basic_string<char> >,
      std::__1::allocator<std::__1::pair<const std::__1::basic_string<char>,
      std::__1::basic_string<char> > > >, 0>' requested here
        return get<ValueType>();
               ^
foo.cpp:15:45: note: in instantiation of function template specialization
      'nlohmann::basic_json<std::map, std::vector, std::__1::basic_string<char>,
      bool, long long, unsigned long long, double, std::allocator,
      adl_serializer>::operator map<std::__1::map<std::__1::basic_string<char>,
      std::__1::basic_string<char>, std::__1::less<std::__1::basic_string<char>
      >, std::__1::allocator<std::__1::pair<const std::__1::basic_string<char>,
      std::__1::basic_string<char> > > >, 0>' requested here
    std::map<std::string, std::string> m2 = j;
                                            ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/string:1342:40: note: 
      candidate constructor
    _LIBCPP_INLINE_VISIBILITY explicit basic_string(const allocator_type& __a)
                                       ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/string:1354:5: note: 
      candidate constructor
    basic_string(basic_string&& __str)
    ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/string:1349:5: note: 
      candidate constructor
    basic_string(const basic_string& __str);
    ^
1 error generated.

One work around I found is using an iterator feature that was presented in another un-related issue. With an iterator I can get access to each key/value pair. Perhaps this is a good work around until the issue is fully resolved

I'm glad it wasn't me being a total newbie. It seemed like I was using valid syntax.

Just for reference - how does your solution look like?

I'll post it once I get back to my home computer. Unfortunately, my day job does not include compilers anymore.

This was my solution:

            const json& rh = j["rightHand"]; 

           for (auto& element : json::iterator_wrapper(rh)) {
                std::cout << element.key() << " maps to " << element.value() << std::endl;
            }

note that if you take the above and do a std::string(element.value()), the same error occurs as you posted above

This is due to the implementation of from_json(CompatibleObjectType), where we call the iterator-range constructor of that type.

It's weird that it works with pair<string, int> though. I suspect an implementation detail of map or pair that uses a different code path for pair<string, string>.

I think we should first convert from all BasicJsonType underlying pairs to CompatibleObjectType underlying pairs explicitely, and then create the CompatibleObjectType from those pairs.

I think this should be tagged as a confirmed bug

@theodelrieu Do you see a way to fix this?

I will try to fix it this morning, I'll take a look at #607 too

I think this issue is still solved with #615, there is a test that converts to map<string, string>.

You are right, this still works. I shall add a regression test and close this issue.

Actually, the test is inside unit-constructor1.cpp, I should have put it in unit-regression.cpp

No, it's fine to have the tests inside the proper functional suite. But a regression test gives me a better feeling on top of it.

Is it possible that there is still an error when using the assignment operator of std::map?
For example:

std::map<std::string, std::string> m1 {{"key", "val"}};

json j = m1;

std::map<std::string, std::string> m2 = j; // everything is fine, like in the unit test

std::map<std::string, std::string> m3;

m3 = j; // compile error ambiguous overload for ‘operator=’

Hello @amibae , the root of this problem is explained in detail in #958.

Hi I think there is still an issue with certain key/value type combinations. I can't seem to get to work.

    //<string, string> works
    std::map<std::string, std::string> map_input1 = {{"hello", "world"}};
    json json_map1(map_input1);
    std::map<std::string, std::string> map_output1 = json_map1;

    //<string, double> works
    std::map<std::string, double> map_input2 = {{"hello", 2.0}};
    json json_map2(map_input2);
    std::map<std::string, double> map_output2 = json_map2;

    //<int, double> doesn't work
    std::map<int, double> map_input3 = {{1, 2.0}};
    json json_map3(map_input3);
    std::map<int, double> map_output3 = json_map3;

EDIT: Or is this due to the fact that int doesn't convert implicitly to string?

@FrotBot What is the compiler error?

/opt/robodev/include/nlohmann/detail/conversions/from_json.hpp: In instantiation of ‘void nlohmann::detail::from_json(const BasicJsonType&, std::pair<_Tp1, _Tp2>&) [with BasicJsonType = nlohmann::basic_json<>; A1 = const int; A2 = double]’:
/opt/robodev/include/nlohmann/detail/conversions/from_json.hpp:288:25:   required from ‘decltype ((nlohmann::detail::from_json(j, val), void())) nlohmann::detail::from_json_fn::call(const BasicJsonType&, T&, nlohmann::detail::priority_tag<1>) const [with BasicJsonType = nlohmann::basic_json<>; T = std::pair<const int, double>; decltype ((nlohmann::detail::from_json(j, val), void())) = void]’
/opt/robodev/include/nlohmann/detail/conversions/from_json.hpp:309:47:   required from ‘void nlohmann::detail::from_json_fn::operator()(const BasicJsonType&, T&) const [with BasicJsonType = nlohmann::basic_json<>; T = std::pair<const int, double>]’
/opt/robodev/include/nlohmann/adl_serializer.hpp:26:30:   required from ‘static void nlohmann::adl_serializer< <template-parameter-1-1>, <template-parameter-1-2> >::from_json(BasicJsonType&&, ValueType&) [with BasicJsonType = const nlohmann::basic_json<>&; ValueType = std::pair<const int, double>; <template-parameter-1-1> = std::pair<const int, double>; <template-parameter-1-2> = void]’
/opt/robodev/include/nlohmann/json.hpp:2570:45:   required from ‘ValueType nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer>::get() const [with ValueTypeCV = std::pair<const int, double>; ValueType = std::pair<const int, double>; typename std::enable_if<(((! nlohmann::detail::is_basic_json<ValueType>::value) && nlohmann::detail::has_from_json<nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer>, ValueType>::value) && (! nlohmann::detail::has_non_default_from_json<nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer>, ValueType>::value)), int>::type <anonymous> = 0; ObjectType = std::map; ArrayType = std::vector; StringType = std::__cxx11::basic_string<char>; BooleanType = bool; NumberIntegerType = long int; NumberUnsignedType = long unsigned int; NumberFloatType = double; AllocatorType = std::allocator; JSONSerializer = nlohmann::adl_serializer]’
/opt/robodev/include/nlohmann/detail/conversions/from_json.hpp:150:5:   required from ‘nlohmann::detail::from_json_array_impl(const BasicJsonType&, CompatibleArrayType&, nlohmann::detail::priority_tag<0>)::<lambda(const BasicJsonType&)> [with BasicJsonType = nlohmann::basic_json<>; CompatibleArrayType = std::map<int, double>]’
/opt/robodev/include/nlohmann/detail/conversions/from_json.hpp:145:51:   [ skipping 3 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
/opt/robodev/include/nlohmann/detail/conversions/from_json.hpp:288:25:   required from ‘decltype ((nlohmann::detail::from_json(j, val), void())) nlohmann::detail::from_json_fn::call(const BasicJsonType&, T&, nlohmann::detail::priority_tag<1>) const [with BasicJsonType = nlohmann::basic_json<>; T = std::map<int, double>; decltype ((nlohmann::detail::from_json(j, val), void())) = void]’
/opt/robodev/include/nlohmann/detail/conversions/from_json.hpp:309:47:   required from ‘void nlohmann::detail::from_json_fn::operator()(const BasicJsonType&, T&) const [with BasicJsonType = nlohmann::basic_json<>; T = std::map<int, double>]’
/opt/robodev/include/nlohmann/adl_serializer.hpp:26:30:   required from ‘static void nlohmann::adl_serializer< <template-parameter-1-1>, <template-parameter-1-2> >::from_json(BasicJsonType&&, ValueType&) [with BasicJsonType = const nlohmann::basic_json<>&; ValueType = std::map<int, double>; <template-parameter-1-1> = std::map<int, double>; <template-parameter-1-2> = void]’
/opt/robodev/include/nlohmann/json.hpp:2570:45:   required from ‘ValueType nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer>::get() const [with ValueTypeCV = std::map<int, double>; ValueType = std::map<int, double>; typename std::enable_if<(((! nlohmann::detail::is_basic_json<ValueType>::value) && nlohmann::detail::has_from_json<nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer>, ValueType>::value) && (! nlohmann::detail::has_non_default_from_json<nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer>, ValueType>::value)), int>::type <anonymous> = 0; ObjectType = std::map; ArrayType = std::vector; StringType = std::__cxx11::basic_string<char>; BooleanType = bool; NumberIntegerType = long int; NumberUnsignedType = long unsigned int; NumberFloatType = double; AllocatorType = std::allocator; JSONSerializer = nlohmann::adl_serializer]’
/opt/robodev/include/nlohmann/json.hpp:2832:30:   required from ‘nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer>::operator ValueType() const [with ValueType = std::map<int, double>; typename std::enable_if<(((((! std::is_pointer<_Ptr>::value) && (! std::is_same<ValueType, nlohmann::detail::json_ref<nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer> > >::value)) && (! std::is_same<ValueType, typename StringType::value_type>::value)) && (! nlohmann::detail::is_basic_json<BasicJsonType>::value)) && (! std::is_same<ValueType, std::initializer_list<typename StringType::value_type> >::value)), int>::type <anonymous> = 0; ObjectType = std::map; ArrayType = std::vector; StringType = std::__cxx11::basic_string<char>; BooleanType = bool; NumberIntegerType = long int; NumberUnsignedType = long unsigned int; NumberFloatType = double; AllocatorType = std::allocator; JSONSerializer = nlohmann::adl_serializer]’
/home/frederik_siepe/rd_root/repos/rd_path_planning/src/rd/path_planner/rd_path_planner.cpp:58:38:   required from here
/opt/robodev/include/nlohmann/detail/conversions/from_json.hpp:265:7: error: use of deleted function ‘std::pair<_T1, _T2>& std::pair<_T1, _T2>::operator=(typename std::conditional<std::__not_<std::__and_<std::is_copy_assignable<_Tp>, std::is_copy_assignable<_T2> > >::value, const std::pair<_T1, _T2>&, const std::__nonesuch_no_braces&>::type) [with _T1 = const int; _T2 = double; typename std::conditional<std::__not_<std::__and_<std::is_copy_assignable<_Tp>, std::is_copy_assignable<_T2> > >::value, const std::pair<_T1, _T2>&, const std::__nonesuch_no_braces&>::type = const std::pair<const int, double>&]’
     p = {j.at(0).template get<A1>(), j.at(1).template get<A2>()};
     ~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/c++/7/bits/stl_algobase.h:64:0,
                 from /usr/include/c++/7/bits/char_traits.h:39,
                 from /usr/include/c++/7/ios:40,
                 from /usr/include/c++/7/istream:38,
                 from /usr/include/c++/7/sstream:38,
                 from /usr/include/c++/7/complex:45,
                 from /usr/include/eigen3/Eigen/Core:80,
                 from /opt/ros/melodic/include/eigen_conversions/eigen_kdl.h:37,
                 from /home/frederik_siepe/rd_root/repos/rd_path_planning/src/rd/path_planner/rd_path_planner.cpp:1:
/usr/include/c++/7/bits/stl_pair.h:378:7: note: declared here
       operator=(typename conditional<

Looks like something is broken with SFINAE checks. Sigh...

I'll fix it on Monday, could you just open a new issue please? Thanks for the report.

This was my solution:

            const json& rh = j["rightHand"]; 

           for (auto& element : json::iterator_wrapper(rh)) {
                std::cout << element.key() << " maps to " << element.value() << std::endl;
            }

This works for me.
Is there any ever better solution on this?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

koemeet picture koemeet  Â·  4Comments

moneroexamples picture moneroexamples  Â·  4Comments

bassosimone picture bassosimone  Â·  3Comments

Prati369 picture Prati369  Â·  4Comments

alienzj picture alienzj  Â·  4Comments