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!
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
//<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.
yes, thank you very much!
https://github.com/nlohmann/json/issues/1372
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?
Most helpful comment
I'm glad it wasn't me being a total newbie. It seemed like I was using valid syntax.