Skip to content

json::value_t can't be a map's key type in VC++ 2015 #486

Description

@Getfree

The following code does not compile in Visual Studio 2015, but compiles fine in GCC.

#include <string>
#include <map>
#include <iostream>

#include "json.hpp"
using JSON = nlohmann::json ;

int main (){
	using namespace std ;
	
	map<JSON::value_t,string> jsonTypes ;

	jsonTypes[JSON::value_t::array] = "array" ;

	cout << jsonTypes[ JSON({"val1", 123, false}) ] << endl ;
}

Wandbox: http://melpon.org/wandbox/permlink/Izdt8DW4UGpVQdUd

Activity

  1. nlohmann commented on Mar 7, 2017

    @nlohmann
    Owner

    Can you please provide the error messages from MSVC?

  2. Getfree commented on Mar 7, 2017

    @Getfree
    Author

    No problem. Here:

    Z:\>cl /EHsc test3.cpp
    test3.cpp
    C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\xstddef(239): error C2593: 'operator <' is ambiguous
    C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\system_error(436): note: could be 'bool std::operator <(const std::error_condition &,const std::error_condition &) noexcept'
    C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\system_error(427): note: or       'bool std::operator <(const std::error_code &,const std::error_code &) noexcept'
    z:\json.hpp(171): note: or       'bool nlohmann::detail::operator <(const nlohmann::detail::value_t,const nlohmann::detail::value_t) noexcept' [found using argument-dependent lookup]
    C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\xstddef(239): note: while trying to match the argument list '(const nlohmann::basic_json<std::map,std::vector,std::string,bool,int64_t,uint64_t,double,std::allocator,nlohmann::adl_serializer>::value_t, const nlohmann::basic_json<std::map,std::vector,std::string,bool,int64_t,uint64_t,double,std::allocator,nlohmann::adl_serializer>::value_t)'
    C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\xstddef(238): note: while compiling class template member function 'bool std::less<_Kty>::operator ()(const _Ty &,const _Ty &) const'
            with
            [
                _Kty=nlohmann::basic_json<std::map,std::vector,std::string,bool,int64_t,uint64_t,double,std::allocator,nlohmann::adl_serializer>::value_t,
                _Ty=nlohmann::basic_json<std::map,std::vector,std::string,bool,int64_t,uint64_t,double,std::allocator,nlohmann::adl_serializer>::value_t
            ]
    C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\map(210): note: see reference to function template instantiation 'bool std::less<_Kty>::operator ()(const _Ty &,const _Ty &) const' being compiled
            with
            [
                _Kty=nlohmann::basic_json<std::map,std::vector,std::string,bool,int64_t,uint64_t,double,std::allocator,nlohmann::adl_serializer>::value_t,
                _Ty=nlohmann::basic_json<std::map,std::vector,std::string,bool,int64_t,uint64_t,double,std::allocator,nlohmann::adl_serializer>::value_t
            ]
    C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\type_traits(421): note: see reference to class template instantiation 'std::less<_Kty>' being compiled
            with
            [
                _Kty=nlohmann::basic_json<std::map,std::vector,std::string,bool,int64_t,uint64_t,double,std::allocator,nlohmann::adl_serializer>::value_t
            ]
    C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\xutility(265): note: see reference to class template instantiation 'std::is_empty<_Ty1>' being compiled
            with
            [
                _Ty1=std::less<nlohmann::basic_json<std::map,std::vector,std::string,bool,int64_t,uint64_t,double,std::allocator,nlohmann::adl_serializer>::value_t>
            ]
    C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\xtree(957): note: see reference to class template instantiation 'std::_Tree_comp_alloc<_Traits>' being compiled
            with
            [
                _Traits=std::_Tmap_traits<nlohmann::basic_json<std::map,std::vector,std::string,bool,int64_t,uint64_t,double,std::allocator,nlohmann::adl_serializer>::value_t,std::string,std::less<nlohmann::basic_json<std::map,std::vector,std::string,bool,int64_t,uint64_t,double,std::allocator,nlohmann::adl_serializer>::value_t>,std::allocator<std::pair<const nlohmann::basic_json<std::map,std::vector,std::string,bool,int64_t,uint64_t,double,std::allocator,nlohmann::adl_serializer>::value_t,std::string>>,false>
            ]
    C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\map(73): note: see reference to class template instantiation 'std::_Tree<std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>>' being compiled
            with
            [
                _Kty=nlohmann::basic_json<std::map,std::vector,std::string,bool,int64_t,uint64_t,double,std::allocator,nlohmann::adl_serializer>::value_t,
                _Ty=std::string,
                _Pr=std::less<nlohmann::basic_json<std::map,std::vector,std::string,bool,int64_t,uint64_t,double,std::allocator,nlohmann::adl_serializer>::value_t>,
                _Alloc=std::allocator<std::pair<const nlohmann::basic_json<std::map,std::vector,std::string,bool,int64_t,uint64_t,double,std::allocator,nlohmann::adl_serializer>::value_t,std::string>>
            ]
    test3.cpp(11): note: see reference to class template instantiation 'std::map<nlohmann::basic_json<std::map,std::vector,std::string,bool,int64_t,uint64_t,double,std::allocator,nlohmann::adl_serializer>::value_t,std::string,std::less<_Kty>,std::allocator<std::pair<const _Kty,_Ty>>>' being compiled
            with
            [
                _Kty=nlohmann::basic_json<std::map,std::vector,std::string,bool,int64_t,uint64_t,double,std::allocator,nlohmann::adl_serializer>::value_t,
                _Ty=std::string
            ]
    
  3. nlohmann commented on Mar 7, 2017

    @nlohmann
    Owner

    Could you try explicitly to pass nlohmann::detail::operator< as Compare template argument to the map?

  4. Getfree commented on Mar 7, 2017

    @Getfree
    Author

    I don't know how to pass the operator itself, but I tried passing a functor, like this:

    #include <string>
    #include <map>
    #include <iostream>
    
    #include "json.hpp"
    using JSON = nlohmann::json ;
    
    int main (){
    	using namespace std ;
    
    	struct value_tCompare {
    		bool operator()(const JSON::value_t& a, const JSON::value_t& b) const{
    			return a < b ;
    		}
    	} ;
    	
    	map<JSON::value_t, string, value_tCompare > jsonTypes ;
    
    	jsonTypes[JSON::value_t::array] = "array" ;
    
    	cout << jsonTypes[ JSON({"val1", 123, false}) ] << endl ;
    }
    

    And the result was this:

    Z:\>cl /EHsc test3.cpp
    test3.cpp
    test3.cpp(13): error C2593: 'operator <' is ambiguous
    C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\system_error(436): note: could be 'bool std::operator <(const std::error_condition &,const std::error_condition &) noexcept'
    C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\system_error(427): note: or       'bool std::operator <(const std::error_code &,const std::error_code &) noexcept'
    z:\json.hpp(171): note: or       'bool nlohmann::detail::operator <(const nlohmann::detail::value_t,const nlohmann::detail::value_t) noexcept' [found using argument-dependent lookup]
    test3.cpp(13): note: while trying to match the argument list '(const nlohmann::basic_json<std::map,std::vector,std::string,bool,int64_t,uint64_t,double,std::allocator,nlohmann::adl_serializer>::value_t, const nlohmann::basic_json<std::map,std::vector,std::string,bool,int64_t,uint64_t,double,std::allocator,nlohmann::adl_serializer>::value_t)'
    

    Then I tried using nlohmann::detail::operator< explicitly inside the functor, and it compiled successfully.

    #include <string>
    #include <map>
    #include <iostream>
    
    #include "json.hpp"
    using JSON = nlohmann::json ;
    
    int main (){
    	using namespace std ;
    
    	struct value_tCompare {
    		bool operator()(const JSON::value_t& a, const JSON::value_t& b) const{
    			return nlohmann::detail::operator<(a,b) ;
    		}
    	} ;
    	
    	map<JSON::value_t, string, value_tCompare > jsonTypes ;
    
    	jsonTypes[JSON::value_t::array] = "array" ;
    
    	cout << jsonTypes[ JSON({"val1", 123, false}) ] << endl ;
    }
    

    This seems to be an argument-dependent lookup issue. For some reason the compiler is not prioritizing nlohmann::detail::operator< over the others.

    Hopefully there is a way to solve it, so we don't need this workaround.

  5. nlohmann commented on Mar 7, 2017

    @nlohmann
    Owner

    This seems to be an issue where @theodelrieu may know more.

  6. theodelrieu commented on Mar 7, 2017

    @theodelrieu
    Contributor

    I will take a look tomorrow, this looks like a MSVC-specific weirdness at first sight

  7. theodelrieu commented on Mar 8, 2017

    @theodelrieu
    Contributor

    There is a workaround mentioned in this StackOverflow thread
    Should we add this to the library?

    namespace std {
    template <>
    struct less<::nlohmann::detail::value_t>
    {
      bool operator()(::nlohmann::detail::value_t lhs, ::nlohmann::detail::value_t rhs) const noexcept
      {
        return ::nlohmann::detail::operator<(lhs, rhs);
      }
    };
    }
  8. nlohmann commented on Mar 8, 2017

    @nlohmann
    Owner

    Is it safe to add this to the std namespace? @gregmarr ?

  9. theodelrieu commented on Mar 8, 2017

    @theodelrieu
    Contributor

    That's a template specialization, it's allowed and safe.

    Plus, this is what the default std::less<nlohmann::detail::value_t> looks like on the other platforms.

  10. self-assigned this
    on Mar 11, 2017
  11. added this to the Release 3.0.0 milestone on Mar 11, 2017
  12. nlohmann commented on Mar 11, 2017

    @nlohmann
    Owner

    The following code now compiles with MSVC 2015 (see https://ci.appveyor.com/project/nlohmann/json/build/1765):

    std::map<json::value_t, std::string> jsonTypes ;
    jsonTypes[json::value_t::array] = "array";

    @Getfree Can you try this version of the code please: f4126e4

  13. Getfree commented on Mar 11, 2017

    @Getfree
    Author

    I added the fixed version to my project and it compiled successfully.

    Many thanks.

  14. added a commit that references this issue on Mar 12, 2017
  15. removed
    solution: proposed fixa fix for the issue has been proposed and waits for confirmation
    on Mar 12, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions