Tessil / ordered-map

C++ hash map and hash set which preserve the order of insertion
MIT License
517 stars 67 forks source link

Compilation error using GCC 8 RC #9

Closed Ptomaine closed 6 years ago

Ptomaine commented 6 years ago

Using MinGW GCC 8 RC from here. There is the compilation error when using the following code:

template<class Key, class T, class Ignore, class Allocator, class Hash = std::hash<Key>, class KeyEqual = std::equal_to<Key>>
using ordered_map = tsl::ordered_map<Key, T, Hash, KeyEqual, Allocator>;

using namespace nlohmann;
using json_ord = basic_json<ordered_map>;

inline json_ord operator "" _json_ord(const char* s, std::size_t n)
{
    return json_ord::parse(s, s + n);
}

inline json_ord::json_pointer operator "" _json_ord_pointer(const char* s, std::size_t n)
{
    return json_ord::json_pointer(std::string(s, n));
}

void main()
{
     auto js { R"({"3":null, "1":"the middle one...", "2":null})"_json_ord };
}

This is the following error:

In file included from C:/MinGW/include/c++/8.0.1/deque:64,
                 from ordered-map/tsl/ordered_map.h:29,
C:/MinGW/include/c++/8.0.1/bits/stl_deque.h: In instantiation of 'class std::deque<std::pair<std::__cxx11::basic_string<char>, nlohmann::basic_json<ordered_map> >, s
td::allocator<std::pair<const std::__cxx11::basic_string<char>, nlohmann::basic_json<ordered_map> > > >':
external/ordered-map/tsl/ordered_hash.h:213:97:   required from 'class tsl::detail_ordered_hash::ordered_hash<std::pair<std::__cxx11::basic_string<char>, nlohmann::basic_j
son<ordered_map> >, tsl::ordered_map<std::__cxx11::basic_string<char>, nlohmann::basic_json<ordered_map>, std::hash<std::__cxx11::basic_string<char> >, std::eq
ual_to<std::__cxx11::basic_string<char> >, std::allocator<std::pair<const std::__cxx11::basic_string<char>, nlohmann::basic_json<ordered_map> > >, std::deque<std::pa
ir<std::__cxx11::basic_string<char>, nlohmann::basic_json<ordered_map> >, std::allocator<std::pair<const std::__cxx11::basic_string<char>, nlohmann::basic_json<nstd:
:ordered_map> > > > >::KeySelect, tsl::ordered_map<std::__cxx11::basic_string<char>, nlohmann::basic_json<ordered_map>, std::hash<std::__cxx11::basic_string<char> >,
 std::equal_to<std::__cxx11::basic_string<char> >, std::allocator<std::pair<const std::__cxx11::basic_string<char>, nlohmann::basic_json<ordered_map> > >, std::deque
<std::pair<std::__cxx11::basic_string<char>, nlohmann::basic_json<ordered_map> >, std::allocator<std::pair<const std::__cxx11::basic_string<char>, nlohmann::basic_js
on<ordered_map> > > > >::ValueSelect, std::hash<std::__cxx11::basic_string<char> >, std::equal_to<std::__cxx11::basic_string<char> >, std::allocator<std::pair<const
std::__cxx11::basic_string<char>, nlohmann::basic_json<ordered_map> > >, std::deque<std::pair<std::__cxx11::basic_string<char>, nlohmann::basic_json<ordered_ma
p> >, std::allocator<std::pair<const std::__cxx11::basic_string<char>, nlohmann::basic_json<ordered_map> > > > >'
external/ordered-map/tsl/ordered_map.h:106:43:   required from 'class tsl::ordered_map<std::__cxx11::basic_string<char>, nlohmann::basic_json<ordered_map>, std::hash
<std::__cxx11::basic_string<char> >, std::equal_to<std::__cxx11::basic_string<char> >, std::allocator<std::pair<const std::__cxx11::basic_string<char>, nlohmann::basic_jso
n<ordered_map> > >, std::deque<std::pair<std::__cxx11::basic_string<char>, nlohmann::basic_json<ordered_map> >, std::allocator<std::pair<const std::__cxx11::ba
sic_string<char>, nlohmann::basic_json<ordered_map> > > > >'
external/json/include/nlohmann/json.hpp:2970:15:   required from 'class nlohmann::basic_json<ordered_map>'
json.hpp.cpp:40:79:   required from here
C:/MinGW/include/c++/8.0.1/bits/stl_deque.h:847:21: error: static assertion failed: std::deque must have the same value_type as its allocator
       static_assert(is_same<typename _Alloc::value_type, _Tp>::value,
                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tessil commented 6 years ago

Effectively, the problem comes from the type in the allocator .

The JSON library has the following line (where ObjectType would be tsl::ordered_map):

using object_t = ObjectType<StringType,
                            basic_json,
                            object_comparator_t,
                            AllocatorType<std::pair<const StringType, basic_json>>>;

Due to its nature (open-addressing hash map), the tsl::ordered_map has to store std::pair<Key, T> instead of std::pair<const Key, T> as done by std::map and std::unorderd_map. It thus needs an AllocatorType<std::pair<StringType, basic_json>> instead of an AllocatorType<std::pair<const StringType, basic_json>>. I overlooked that in my reply on the nlohmann/json library and previous versions of GCC didn't have this check.

One way to overcome this would be to ignore the allocator (replace std::allocator with yours if you don't use the default one):

template<class Key, class T, class Ignore1, class Ignore2, class Hash = std::hash<Key>, class KeyEqual = std::equal_to<Key>, class Allocator = std::allocator<std::pair<Key, T>>>
using ordered_map = tsl::ordered_map<Key, T, Hash, KeyEqual, Allocator>;

I have to check if there is a better way, but this one should works.

Ptomaine commented 6 years ago

Thanks! This works for me! 👍

Tessil commented 6 years ago

I updated my reply on the nlohmann/json issue.

It's better to prefer this way so that when a specific allocator is used in nlohmann::json, it will also be used by tsl::ordered_map without requiring any change:

template<class Key, class T, class Ignore, class Allocator, 
         class Hash = std::hash<Key>, class KeyEqual = std::equal_to<Key>>
using ordered_map = tsl::ordered_map<Key, T, Hash, KeyEqual, 
                                     typename std::allocator_traits<Allocator>::template 
                                     rebind_alloc<std::pair<Key, T>>>;
Ptomaine commented 6 years ago

WOW! Even better! Thanks a lot! 👍