2015-04-30 11 views
16

Con un tipo regolare, intendo la definizione di Stepanov in Elementi di programmazione, in sostanza, che esiste il concetto di uguaglianza e che gli oggetti che sono copie l'uno dell'altro sono uguali.C++ 11: Ci sono ragioni per cui alcuni tipi regolari non dovrebbero avere `std :: hash` specializzato?

Quindi, quando si dispone di un tipo regolare T, e il rapporto uguaglianza è transitiva (a == b & & b == c => a == c), è possibile definire una (non banale) funzione di hash che è coerente con la definizione di uguaglianza (a == b => h (a) == h (b)). Sempre.

Ma lo standard non include molte specializzazioni std::hash. Per esempio. std::complex non ne ha uno e nessuno dei due ha i contenitori, con le notevoli eccezioni di vector<bool> e bitset.

Quindi mi chiedo quale sia il principio di progettazione qui.

Oppure, chiesto in modo diverso: ci sono motivi per non fornire specializzazioni std::hash per i propri tipi, a condizione che siano regolari e che l'uguaglianza sia transitiva?

+1

Certo, è sempre possibile definire una funzione di hash coerente: 'size_t operator() (T & const) const {return 0; } 'La domanda è, puoi sempre definire quella che è buona per un tipo arbitrario? – Barry

+0

'vector ' non è implementato come 'vector' di' bool's. È una specializzazione di template che si basa su 'int' per salvare diversi' bool's (suppongo 32). È invariante rispetto a tutti i parametri del template (e ai tipi sottostanti ''std :: hash'), penso che sia il motivo per cui viene fornita una specializzazione. – mike

+0

Nella libreria standard vi sono diversi tipi che hanno [richieste permanenti aperte] (https://cplusplus.github.io/LWG/lwg-active.html#1025) per specializzare 'std :: hash' – CoryKramer

risposta

0

Fornire specializzazione per i tipi proprio non ha senso, se sono classi template, dal momento che la funzione di hash (con alta probabilità molto alto) dipende anche dal tipo parametri del modello, che sono sconosciute.

E non ci sono parametri del modello, oi parametri del modello sono limitati a determinati tipi

// provide no implementation to restrict all types 
template<typename T> container; 

// int is allowed 
template<> container<int> { 
    ... 
} 

// double is allowed 
template<> container<double> { 
    ... 
} 

fornendo una specializzazione di std::hash è possibile, poiché le implementazioni delle classi (o le classi modello instanced) sono noti , come lo è per vector<bool> in contrasto con complex<T>.

+0

Cosa c'è di sbagliato in 'namespace std {template struch hash > {using result_type = size_t; using argomento_type = complex ; result_type operator() (const argument_type & a) const {std :: hash hash; size_t result = hash (a.real()) + 0x9e3779b9; risultato^= hash (a.imag()) + 0x9e3779b9 + (risultato << 6) + (risultato >> 2); ritorno risultato; }}; } '? –

+0

Qui la versione formattata: http://pastebin.com/CcwKmEMy – mike

+0

la riga 'std :: hash hash;' richiede che ci sia una specializzazione 'std :: hash' per' T', usa questa specializzazione per creare una specializzazione per 'complesso ', ma come si può sapere che ciò produrrebbe un'implementazione efficace? – mike

2

Sì.

Quando un tipo ha le seguenti due proprietà non credo che si dovrebbe definire std::hash:

  • Non c'è modo efficace per creare costantemente un hash di qualità che copre tutti i dati utilizzati per descrivere l'uguaglianza .

  • Non esiste un modo efficace e/o intuitivo per selezionare un sottoinsieme di dati coerente in hash.

+0

In realtà, 'std :: hash ' può essere implementato in * linear time *, mentre 'operator ==' ha il peggior cast * quadratic time *. Basta eliminare singoli oggetti e utilizzare un combinatore di hash commutativo (aggiunta non firmata, * non * xor). –

+0

@ MarcMutz-mmutz Non importa il mio primo commento: se la funzione di hash crea valori uniformi, l'aggiunta va bene. Vedrò se riesco a trovare un esempio migliore, penso che le mie proprietà stiano bene. – orlp

Problemi correlati