2012-08-03 12 views
5

Devo usare unordered_set per un progetto piuttosto grande, e per assicurarmi che lo stia usando correttamente ho provato un piccolo esempio.Dichiarare la funzione di hash per unordered_set in C++?

#include <iostream> 
#include <unordered_set> 
using namespace std; 

class Foo { 
    private: 
    int x; 
    public: 
    Foo(int in) {x = in;} 
    bool operator==(const Foo& foo) const {return x == foo.x;} 
    size_t hash(const Foo& foo) const {return x;} 
}; 

int main() { 
    Foo f1(3); 
    unordered_set<Foo> s; 
    s.insert(f1); 
    return 0; 
} 

Quando compilo ottengo:

/tmp/cc3KFIf4.o: In function `std::__detail::_Hash_code_base<Foo, Foo, std::_Identity<Foo>, std::equal_to<Foo>, std::hash<Foo>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, false>::_M_hash_code(Foo const&) const': 
hashset.cc:(.text._ZNKSt8__detail15_Hash_code_baseI3FooS1_St9_IdentityIS1_ESt8equal_toIS1_ESt4hashIS1_ENS_18_Mod_range_hashingENS_20_Default_ranged_hashELb0EE12_M_hash_codeERKS1_[std::__detail::_Hash_code_base<Foo, Foo, std::_Identity<Foo>, std::equal_to<Foo>, std::hash<Foo>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, false>::_M_hash_code(Foo const&) const]+0x19): undefined reference to `std::hash<Foo>::operator()(Foo) const' 
/tmp/cc3KFIf4.o: In function `std::__detail::_Hash_code_base<Foo, Foo, std::_Identity<Foo>, std::equal_to<Foo>, std::hash<Foo>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, false>::_M_bucket_index(std::__detail::_Hash_node<Foo, false> const*, unsigned int) const': 
hashset.cc:(.text._ZNKSt8__detail15_Hash_code_baseI3FooS1_St9_IdentityIS1_ESt8equal_toIS1_ESt4hashIS1_ENS_18_Mod_range_hashingENS_20_Default_ranged_hashELb0EE15_M_bucket_indexEPKNS_10_Hash_nodeIS1_Lb0EEEj[std::__detail::_Hash_code_base<Foo, Foo, std::_Identity<Foo>, std::equal_to<Foo>, std::hash<Foo>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, false>::_M_bucket_index(std::__detail::_Hash_node<Foo, false> const*, unsigned int) const]+0x28): undefined reference to `std::hash<Foo>::operator()(Foo) const' 
collect2: ld returned 1 exit status 

Sembra che non sta vedendo la mia funzione di hash, ma ho pensato "hash" era il nome della funzione di default. Ho definito correttamente l'hash? O devo dichiarare esplicitamente una classe hash separata come secondo argomento template?

+1

La funzionalità di hash viene passata come parametro di modello aggiuntivo. È necessario (preferibilmente) un funtore e si eseguono 'unordered_set (FooHasher());' – Xeo

risposta

8

In alternativa al suggerimento di Xeo nei commenti, è possibile fornire una specializzazione per std::hash prima di creare un'istanza dello unordered_set.

namespace std { 
    template <> 
    struct hash<Foo> { 
     size_t operator() (const Foo &f) const { return f.hash(f); } 
    }; 
} 

Il parametro foo al metodo hash sembra estranea a me, ma ho implementato la specializzazione per l'interfaccia che hai fornito.

+0

Ok, grazie, ha funzionato. In realtà non ho fatto in modo che la mia funzione di hash prendesse un parametro in più, cioè un errore di battitura. Dovrebbe essere size_t hash() const {return x;} L'unica cosa di cui sono confuso è perché non posso semplicemente creare un hash() come ho fatto con operator ==()? Per operatore == Non ho dovuto fare nulla in più. – user1575106

+0

@ user1575106: API diverse avranno requisiti diversi. Gli scrittori standard non possono soddisfare il desiderio di tutti, e l'interfaccia data rende facile provare diversi algoritmi di hash senza modificare la classe. – jxh

Problemi correlati