In gcc 12.2, the following C++ code gives me an error. The gist of the complaint is that "hash function must be invocable with an argument of key type":
#include <cstddef>
#include <unordered_map>
#include <functional>
struct OUTER {
class KEY {
public:
bool operator==(KEY const&) const;
struct Hash {
auto operator()(KEY const&) const {
// Give the hash for ten -- why not?
return std::hash<size_t>{}(10);
};
};
};
std::unordered_map<KEY, int, KEY::Hash> m;
bool test(KEY const& ident) { return m.end() != m.find(ident); }
};
The error message is:
In file included from /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/hashtable.h:35,
from /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/unordered_map:46,
from <source>:2:
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/hashtable_policy.h: In instantiation of 'std::__detail::_Hash_code_base<_Key, _Value, _ExtractKey, _Hash, _RangeHash, _Unused, __cache_hash_code>::__hash_code std::__detail::_Hash_code_base<_Key, _Value, _ExtractKey, _Hash, _RangeHash, _Unused, __cache_hash_code>::_M_hash_code(const _Key&) const [with _Key = OUTER::KEY; _Value = std::pair<const OUTER::KEY, int>; _ExtractKey = std::__detail::_Select1st; _Hash = OUTER::KEY::Hash; _RangeHash = std::__detail::_Mod_range_hashing; _Unused = std::__detail::_Default_ranged_hash; bool __cache_hash_code = true; __hash_code = long unsigned int]':
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/hashtable.h:1653:46: required from 'std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::iterator std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::find(const key_type&) [with _Key = OUTER::KEY; _Value = std::pair<const OUTER::KEY, int>; _Alloc = std::allocator<std::pair<const OUTER::KEY, int> >; _ExtractKey = std::__detail::_Select1st; _Equal = std::equal_to<OUTER::KEY>; _Hash = OUTER::KEY::Hash; _RangeHash = std::__detail::_Mod_range_hashing; _Unused = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<true, false, true>; iterator = std::__detail::_Insert_base<OUTER::KEY, std::pair<const OUTER::KEY, int>, std::allocator<std::pair<const OUTER::KEY, int> >, std::__detail::_Select1st, std::equal_to<OUTER::KEY>, OUTER::KEY::Hash, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<true, false, true> >::iterator; key_type = OUTER::KEY]'
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/unordered_map.h:869:25: required from 'std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::iterator std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::find(const key_type&) [with _Key = OUTER::KEY; _Tp = int; _Hash = OUTER::KEY::Hash; _Pred = std::equal_to<OUTER::KEY>; _Alloc = std::allocator<std::pair<const OUTER::KEY, int> >; iterator = std::__detail::_Insert_base<OUTER::KEY, std::pair<const OUTER::KEY, int>, std::allocator<std::pair<const OUTER::KEY, int> >, std::__detail::_Select1st, std::equal_to<OUTER::KEY>, OUTER::KEY::Hash, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<true, false, true> >::iterator; key_type = OUTER::KEY]'
<source>:17:59: required from here
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/hashtable_policy.h:1268:23: error: static assertion failed: hash function must be invocable with an argument of key type
1268 | static_assert(__is_invocable<const _Hash&, const _Key&>{},
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/hashtable_policy.h:1268:23: note: 'std::__is_invocable<const OUTER::KEY::Hash&, const OUTER::KEY&>()' evaluates to false
Compiler returned: 1
Since OUTER::KEY::Hash::operator() takes KEY const& as its argument type, shouldn't I be good?
I expected the above code to work since my hash function DOES accept the key type as an argument.
In fact, I received an error!
Declaring an explicit return type for
OUTER::KEY::Hash::operator()seems to fix the problem.std::hashobjects generally returnsize_t, so that is a good candidate for the return type here.I don't know the exact cause of the error, though, since very similar code seems to compile if
class OUTERis removed.