2013-11-24 13 views
16

La libreria standard implementa std :: hash come una struttura di template specializzata per diversi tipi. È usato così:Perché std :: hash è una struct al posto di una funzione?

#include <iostream> 
#include <functional> 

int main() 
{ 
    std::hash<int> hasher; 
    std::cout << hasher(1337) << std::endl; 

    return 0; 
} 

La mia domanda è qual è il ragionamento dietro questa scelta di design. Perché non è implementata come una funzione template e utilizzato in questo modo:

#include <iostream> 
#include <functional> 

int main() 
{ 
    std::cout << std::hash<int>(1337) << std::endl; 

    return 0; 
} 
+0

i 2 esempi sono identici, l'unica differenza è che nel secondo l'oggetto è senza nome. – user2485710

+0

I contenitori associati non ordinati hanno un parametro del tipo di modello per specificare l'hash; questo permette di usare oggetti hash con stato (ad esempio usando un valore speciale che è XORed sull'hash). Ottenere il tipo di specializzazione di un modello di funzione non ha una bella sintassi. – dyp

+1

@ user2485710 Il primo esempio viene compilato, il secondo no. Il secondo dovrebbe essere scritto come 'std :: hash () (1337)' per usare una struttura temporanea senza nome. – hvd

risposta

16

Ci sono, diverse ragioni, ognuno abbastanza buono da solo la scelta:

  1. È possibile specializzare parzialmente i modelli di classe, ma è possibile solo modelli di funzioni completamente specializzati (almeno, fino ad ora). Pertanto, è possibile fornire una sostituzione per un'intera suite di argomenti modello correlati con std::hash<T> come modello di classe. Nota che il sovraccarico parziale non aiuta perché la funzione di hash dovrebbe essere specificata in qualche modo come un oggetto che non può essere eseguito con funzioni sovraccaricate (a meno che non siano accessibili tramite un oggetto ma questo è ciò che è differenziato).
  2. I contenitori associativi non ordinati sono parametrizzati con un'entità statica (che può anche essere personalizzata dinamicamente se il tipo specifico lo supporta), operazione che è più semplice utilizzando modelli di classe.
  3. Poiché le entità utilizzate per la funzione di hash sono personalizzabili, la scelta è tra l'utilizzo di un puntatore di tipo o di funzione per la personalizzazione. I puntatori di funzione sono spesso difficili da allineare mentre le funzioni di membro inline di un tipo sono banali in linea, migliorando le prestazioni per funzioni semplici come il calcolo di un semplice hash piuttosto un po '.
+3

Per essere corretti, l'hash predefinito avrebbe potuto chiamare una funzione che quindi per i tipi non supportati provare a chiamare il metodo '.hash()', che consentirebbe tutto quanto sopra, consentire l'hashing di adl (che è meglio che forzare un Iniezione 'std'), e consentire agli oggetti di auto' hash' se lo desiderano. Ma questo viola KISS, anche se corrisponde a come 'less' e' begin' funzionano. – Yakk

4

una funzione template non può essere parzialmente specializzata per i tipi, mentre std::hash specializzati per tipi diversi come modello di classe.

E, in questo modo basato classe modello, si può fare qualche meta di programmazione come l'accesso a ritornare tipo e tipo di chiave come di seguito:

std::hash<X>::argument_type 
std::hash<X>::result_type