I need to write std::hash implementation for my own type, and this implementation has to be fast. Please consider code example:
#include <unordered_set>
#include <cstdint>
struct Vector
{
float x, y, z;
};
inline bool operator ==( const Vector & a, const Vector & b )
{
return a.x == b.x && a.y == b.y && a.z == b.z;
}
namespace std
{
template<>
struct hash<Vector>
{
size_t operator()( Vector const& p ) const noexcept
{
return
( (size_t)*reinterpret_cast<const std::uint64_t*>(&p.x) ) ^
( (size_t)*reinterpret_cast<const std::uint32_t*>(&p.z) << 16 );
}
};
}
int main()
{
std::unordered_set<Vector> s;
s.insert( Vector{ 0, 0, 0 } );
s.insert( Vector{ 0, 0, 1 } );
return 0;
}
It works well on practice (when float is 32bit wide), but gcc emits a couple of warnings about it:
main.cpp: In member function 'std::size_t std::hash<Vector>::operator()(const Vector&) const':
main.cpp:23:24: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
23 | ( (size_t)*reinterpret_cast<const std::uint64_t*>(&p.x) ) ^
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:24:24: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
24 | ( (size_t)*reinterpret_cast<const std::uint32_t*>(&p.z) << 16 );
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Is it safe to just suppress the warnings? Or there is a better way to write similar code without sacrificing the performance?