c++stlunordered-mapunordered-multimap

Trouble definining hash function for custom type in unordered_multimap on MacOS


So I want to use a custom type (here, SWrapper) as the key type for an unordered_multimap. I've defined a hash class, derived from the standard hashing function for strings, and included the hashing class in the type of the multimap. Some code that reproduces the error is displayed below. This compiles on Arch Linux with both g++ and clang++, but on MacOS with clang++, I get errors:

#include <unordered_map>
#include <functional>
#include <string>

class SWrapper {
    public:
    SWrapper() {
        (*this).name = "";
    }

    SWrapper(std::string name) {
        (*this).name = name;
    }

    bool operator==(SWrapper const& other) {
        return (*this).name == other.name;
    }

    std::string name;
};

class SWrapperHasher {
    size_t operator()(SWrapper const& sw) const {
        return std::hash<std::string>()(sw.name);
    }
};

int main(int argc, char* argv[]) {
    auto mm = std::unordered_multimap<SWrapper, int, SWrapperHasher>();
    return 0;
}

Running g++ -std=c++11 -Wall -Wpedantic -Wextra hash_map_test.cpp -o hash_map_test on Arch Linux (or clang++) compiles the code with no errors. However, on MacOS, using the same command, I get the following error message:

In file included from hash_map_test.cpp:1:
In file included from /Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/unordered_map:408:
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/__hash_table:868:5: error: 
      static_assert failed due to requirement 'integral_constant<bool, false>::value' "the
      specified hash does not meet the Hash requirements"
    static_assert(__check_hash_requirements<_Key, _Hash>::value,
    ^             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/__hash_table:883:1: note: in
      instantiation of template class
      'std::__1::__enforce_unordered_container_requirements<SWrapper, SWrapperHasher,
      std::__1::equal_to<SWrapper> >' requested here
typename __enforce_unordered_container_requirements<_Key, _Hash, _Equal>::type
^
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/unordered_map:1682:26: note: while
      substituting explicitly-specified template arguments into function template
      '__diagnose_unordered_container_requirements'
    static_assert(sizeof(__diagnose_unordered_container_requirements<_Key, _Hash, _Pred>(...
                         ^
hash_map_test.cpp:29:15: note: in instantiation of template class
      'std::__1::unordered_multimap<SWrapper, int, SWrapperHasher, std::__1::equal_to<SWrapper>,
      std::__1::allocator<std::__1::pair<const SWrapper, int> > >' requested here
    auto mm = std::unordered_multimap<SWrapper, int, SWrapperHasher>();
              ^
1 error generated.

I've tried interpreting the error message, but I'm really at a loss of what to make of it. If anyone has any suggestions as to what's going on here, and how I can work around this on MacOS, it'd be greatly appreciated!


Solution

  • The compiler's complaint unfortunately does not say which requirement was not met. In this case, the problem comes from SWrapperHasher::operator() being private. Marking that public (changing class to struct does this implicitly) makes the unordered map legal.