By failing I mean it is giving a repeated value for different group of double. The three doubles are x, y and z of a vertex. I have a list of vertices and using the hash created from the doubles as a key in the map. I was wondering if a more reliable hash combine function for this specific application exists.
template <class T> inline void hash_combine(std::size_t& seed, T const& v) { seed ^= std::hash<T>()(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2); } 1 Answer
I have a list of vertices and using the hash created from the doubles as a key in the map.
Not the best use of a hash, in the sense of what std::hash or boost::hash represents.
You're looking for uniqueness. A hash in this sense is not unique.
I was wondering if a more reliable hash combine function for this specific application exists.
Not unless the hash space has a 1:1 correlation with the space of possible values of z, y and z - which essentially means using the vertex itself as the identifier.
Summary:
If you want a container indexed by unique vertices, you may want to consider a std::unordered_map. You will need to provide an equality operator.
An example:
#include <boost/functional/hash.hpp> // see below #include <tuple> #include <unordered_map> #include <string> // a simple Vertex class struct Vertex { double x, y, z; }; // a useful general-purpose accessor auto as_tuple(Vertex const& v) -> decltype(auto) { return std::tie(v.x, v.y, v.z); } // equality implemented in terms of tuple, for simplicity bool operator==(Vertex const& l , Vertex const& r) { return as_tuple(l) == as_tuple(r); } // hash_value implemented in terms of tuple, for consistency and simplicity std::size_t hash_value(Vertex const& v) { using boost::hash_value; return hash_value(as_tuple(v)); } // the boring bit - injecting a hash specialisation into the std:: namespace // but let's derive from boost's hash class, which is much better // in that it allows easy hashing using free functions namespace std { template<> struct hash<::Vertex> : boost::hash<::Vertex> {}; } using vertex_map = std::unordered_map<Vertex, std::string>; int main() { auto m = vertex_map(); m[{0, 0, 0}] = "Sol"; m[{1, 3, 5}] = "Mars"; m[{100.4, 343.2, 92.44}] = "Pluto"; } Note: The numbers above are in Zargian NonLinear Megaunits - you won't find them in any Earthbound textbook on the Solar System.