I try to write the some custom function than allow to use my custom structure in the unordered_set template.
I have the structure:
struct test_record {
int value;
std::string name;
};
And the hash operator:
namespace std {
template<> struct hash<test_record> {
using argument_type = test_record;
using result_type = size_t;
size_t operator()(const test_record& r) const {
const std::hash<std::string> str_hash_fn;
const std::hash<int> int_hash_fn;
const size_t result = str_hash_fn(r.name) ^ int_hash_fn(r.value);
return result;
}
};
};
Use it like:
int main()
{
std::unordered_set <test_record> myrecordsset;
myrecordsset.insert({ 1, "one" }); // error!
}
But the compiler throws the error message:
1>E:\Development\Visual Studio\VC\Tools\MSVC\14.25.28610\include\xstddef(91,22): error C2676: binary '==': 'const _Ty' does not define this operator or a conversion to a type acceptable to the predefined operator 1> with 1>
[ 1> _Ty=test_record 1> ] 1>E:\Development\Visual Studio\VC\Tools\MSVC\14.25.28610\include\xstddef(90): message : while compiling class template member function 'bool std::equal_to::operator ()(const _Ty &,const _Ty &) const' 1> with 1> [ 1> _Ty=test_record 1>
] 1>E:\Development\Visual Studio\VC\Tools\MSVC\14.25.28610\include\xhash(164): message : see reference to function template instantiation 'bool std::equal_to::operator ()(const _Ty &,const _Ty &) const' being compiled 1> with 1> [ 1>
_Ty=test_record 1> ] 1>E:\Development\Visual Studio\VC\Tools\MSVC\14.25.28610\include\xmemory(1318): message : see reference to class template instantiation 'std::equal_to' being compiled 1>E:\Development\Visual Studio\VC\Tools\MSVC\14.25.28610\include\xmemory(1318): message : see reference to variable template 'const bool is_empty_v >' being compiled 1>E:\Development\Visual Studio\VC\Tools\MSVC\14.25.28610\include\unordered_set(30): message : see reference to class template instantiation 'std::_Uhash_compare<_Kty,_Hasher,_Keyeq>' being compiled 1>
with 1> [ 1> _Kty=test_record, 1>
_Hasher=std::hash, 1> _Keyeq=std::equal_to 1> ] 1>E:\Development\Visual Studio\VC\Tools\MSVC\14.25.28610\include\xhash(342): message : see reference to class template instantiation 'std::_Uset_traits<_Kty,std::_Uhash_compare<_Kty,_Hasher,_Keyeq>,_Alloc,false>' being compiled 1> with 1> [ 1>
_Kty=test_record, 1> _Hasher=std::hash, 1> _Keyeq=std::equal_to, 1> _Alloc=std::allocator 1> ] 1>E:\Development\Visual Studio\VC\Tools\MSVC\14.25.28610\include\unordered_set(65): message : see reference to class template instantiation 'std::_Hash,_Alloc,false>>' being compiled 1> with 1> [ 1>
_Kty=test_record, 1> _Hasher=std::hash, 1> _Keyeq=std::equal_to, 1> _Alloc=std::allocator 1> ] 1>E:\Development_Projects\ConsoleApplication1\ConsoleApplication1\ConsoleApplication1.cpp(20): message : see reference to class template instantiation 'std::unordered_set,std::equal_to,std::allocator>' being compiled
What wrong with it? Why the compiler require the equal_to operator in a unordered_set?
The point of a set is that it contatins no two identical objects. Identity cannot be determined though by just looking at the hash, so you need a concrete equality comparasion. C++ requires that you explicitly define equality for your class in case you need any special behaviour.
Adding this should do the trick:
namespace std {
template<> struct equal_to<test_record> {
using argument_type = test_record;
using result_type = bool;
constexpr bool operator()(const test_record &lhs, const test_record &rhs) const {
return (lhs.name == rhs.name) && (lhs.value == rhs.value);
}
};
};