2009-03-15 15 views
22

Come posso consentire all'implementazione STL di prelevare i miei tipi personalizzati? Su MSVC, c'è una classe std::tr1::hash, che posso parzialmente specializzato utilizzandoCome estendere std :: tr1 :: hash per i tipi personalizzati?

namespace std 
{ 
    namespace tr1 
    { 
     template <> 
     struct hash<MyType> 
     { ... }; 
    } 
} 

Ma è questo il modo consigliato? Inoltre, funziona anche con l'implementazione di GCC? Per boost::hash, è sufficiente fornire una funzione gratuita size_t hash_value (const MyType&), c'è qualcosa di simile per l'implementazione TR1?

+0

C'è un modo per estendere std :: hash per i tipi definiti dall'utente con i costruttori di copia privati? Inoltre, c'è un modo per estenderlo con un operatore() che prende un riferimento const invece di val? –

+0

Qual è il problema con la specializzazione del modello? Non prendi una copia del tuo oggetto (lo passi per riferimenti), quindi nessun problema - e l'operatore() prende un valore const o valore, qualunque cosa tu voglia. Guarda la risposta di Phil Nash, che prende l'oggetto come const ref. – Anteru

risposta

4

Sì, questo funzionerà anche per GCC. Lo sto usando in un progetto più grande e funziona senza problemi. È anche possibile fornire la propria classe di hashing personalizzata per i contenitori TR1, ma è specificato che std :: tr1 :: hash <> è la classe hashing predefinita. Specializzarlo per i tipi personalizzati sembra il modo naturale per estendere la funzionalità di hashing standard.

3

Poiché non si aggiunge allo spazio dei nomi della libreria std, ma si forniscono solo le specializzazioni, quindi è perfettamente OK.

Se si desidera fornire un approccio di hashing più generico (ad esempio hash per le tuple in generale), dare un'occhiata a Boost Fusion. Here is a simple example, che funzionerà per la maggior parte dei casi (probabilmente con l'eccezione per la tupla di tuple)

21

Stavo cercando di calcolare la sintassi esatta per fare ciò con i contenitori associativi non ordinati (utilizzando anche GCC, poiché l'OP era chiedere) e rispondere a questa domanda.

Sfortunatamente non è andato giù al livello di dettaglio che volevo. Guardando attraverso le intestazioni gcc su come hanno implementato le funzioni standard di hash, l'ho fatto funzionare. In considerazione della scarsità di esempi (almeno al momento della scrittura) sul web ho pensato che questo sarebbe un buon posto come un altro per inviare il mio esempio (che posso confermare opere con GCC):


namespace std { namespace tr1 
{ 
    template <> 
    struct hash<MyType> : public unary_function<MyType, size_t> 
    { 
     size_t operator()(const MyType& v) const 
     { 
      return /* my hash algorithm */; 
     } 
    }; 
}} 

(avviso ci sono due spazi dei nomi qui - questo è solo il mio convenzione per collassare namespace annidati)

0

Il seguente frammento di codice mostra come specializzarsi std::tr1::unordered_map alla mappatura boost::const_string<char> a void* analogamente con quanto std::string viene assegnata.

#include <boost/const_string/const_string.hpp>  
typedef class boost::const_string<char> csc; 

namespace std 
{ 
namespace tr1 
{ 
template <> 
struct hash<csc> { 
public: 
    size_t operator()(const csc & x) const { 
     return std::_Hash_impl::hash(x.data(), x.size()); 
    } 
}; 
} 
} 

typedef std::tr1::unordered_map<csc, void*> Map; 
typedef Map::value_type Dual; ///< Element Type. 
Problemi correlati