2010-04-07 11 views
61

C++ 0x aggiunge hash<...>(...).Come si combinano i valori hash in C++ 0x?

Non sono riuscito a trovare una funzione hash_combine, come presentato in boost. Qual è il modo più pulito per implementare qualcosa di simile? Forse, usando C++ 0x xor_combine?

+0

Possibile duplicato di [Come specializzare std :: hash per tipi definiti dall'utente?] (Https://stackoverflow.com/questions/24361884/how-to-specialize-stdhasht-for-user-defined-types) – Raedwald

+0

Una specializzazione di 'std :: hash' deve necessariamente combinare il sub h ceneri dei membri dei dati. Tutte le prove e i ragionamenti applicati si applicano ad una funzione 'hash_combine'. – Raedwald

+0

@Raedwald Vedo ora che quella era una delle sue sottoquestioni, ma per essere onesti, la sua domanda è periferica e indiretta. Aggiungi la tua risposta qui se hai qualcosa da aggiungere. –

risposta

63

Beh, basta farlo come i ragazzi spinta lo ha fatto:

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ì, questo è il meglio che potrei fare anche io. Non capisco come il comitato degli standard abbia rifiutato qualcosa di così ovvio. –

+8

@Neil: sono d'accordo. Penso che una soluzione semplice per loro sarebbe il requisito della libreria di avere un hash per 'std :: pair' (o' tuple', anche). Calcolerebbe l'hash di ogni elemento, quindi li combinerebbe. (E nello spirito della libreria standard, in un modo definito di implementazione.) – GManNickG

+3

Ci sono molte cose ovvie omesse dallo standard. Il processo di revisione intensiva tra pari rende difficile ottenere quelle piccole cose fuori dalla porta. – stinky472

20

io condividere qui dal momento che può essere utile ad altri che cercano per questa soluzione: a partire da @KarlvonMoor risposta, ecco una versione modello variadic, che è terser nel suo utilizzo, se è necessario combinare diversi valori insieme:

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...); 
} 

Usage:

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

Questo è stato scritto in origine per realizzare una macro variadic per rendere facilmente i tipi personalizzati hashable (che credo sia uno degli usi primari di una funzione 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;\ 
      }\ 
     };\ 
    } 

Usage:

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 
Problemi correlati