2010-04-07 22 views
61

C++ 0x agrega hash<...>(...).¿Cómo combino valores hash en C++ 0x?

No he podido encontrar una función hash_combine, como se presenta en boost. ¿Cuál es la forma más limpia de implementar algo como esto? Quizás, usando C++ 0x xor_combine?

+0

Posible duplicado de [¿Cómo especializar std :: hash para tipos definidos por el usuario?] (Https://stackoverflow.com/questions/24361884/how-to-specialize-stdhasht-for-user-defined-types) – Raedwald

+0

Una especialización de 'std :: hash' tiene que combinar inherentemente el sub h cenizas de los miembros de datos. Toda la evidencia y el razonamiento aplicados allí se aplican a una función 'hash_combine'. – Raedwald

+0

@Raedwald Veo ahora que esa fue una de sus preguntas, pero para ser justos, su pregunta es perifrástica e indirecta. Agregue su respuesta aquí si tiene algo que agregar. –

Respuesta

63

Bueno, sólo lo hacen como los chicos a impulsar lo hizo:

template <class T> 
inline void hash_combine(std::size_t& seed, const T& v) 
{ 
    std::hash<T> hasher; 
    seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2); 
} 
+15

sí, eso es lo mejor que podría hacer también. No entiendo cómo el comité de normas rechazó algo tan obvio. –

+8

@Neil: Estoy de acuerdo. Creo que una solución simple para ellos sería el requisito de que la biblioteca tenga un hash para 'std :: pair' (o' tuple', incluso). Calcularía el hash de cada elemento, luego los combinaría. (Y en el espíritu de la biblioteca estándar, en una implementación definida). – GManNickG

+3

Hay muchas cosas obvias omitidas en el estándar. El proceso de revisión intensiva por pares hace que sea difícil sacar esas pequeñas cosas de la puerta. – stinky472

20

lo voy a compartir aquí, ya que puede ser útil para otros que buscan esta solución: a partir de @KarlvonMoor respuesta, aquí está una versión de la plantilla variadic, que es más concisa en su uso si usted tiene que combinar varios valores juntos:

inline void hash_combine(std::size_t& seed) { } 

template <typename T, typename... Rest> 
inline void hash_combine(std::size_t& seed, const T& v, Rest... rest) { 
    std::hash<T> hasher; 
    seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2); 
    hash_combine(seed, rest...); 
} 

uso:

std::size_t h=0; 
hash_combine(h, obj1, obj2, obj3); 

Esto fue escrito originalmente para implementar una macro variadic para hacer fácilmente tipos personalizados hashable (que creo que es uno de los usos principales de una función hash_combine):

#define MAKE_HASHABLE(type, ...) \ 
    namespace std {\ 
     template<> struct hash<type> {\ 
      std::size_t operator()(const type &t) const {\ 
       std::size_t ret = 0;\ 
       hash_combine(ret, __VA_ARGS__);\ 
       return ret;\ 
      }\ 
     };\ 
    } 

Uso:

struct SomeHashKey { 
    std::string key1; 
    std::string key2; 
    bool key3; 
}; 

MAKE_HASHABLE(SomeHashKey, t.key1, t.key2, t.key3) 
// now you can use SomeHashKey as key of an std::unordered_map