2012-08-03 11 views
5

Tengo que usar unordered_set para un proyecto bastante grande, y para asegurarme de que lo estaba usando correctamente probé un pequeño ejemplo.¿Declarar la función hash para unordered_set en 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; 
} 

Cuando compilo me sale:

/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 

Parece como si no lo está viendo mi función hash, pero pensé "control" era el nombre de la función por defecto. ¿Definí el hash correctamente? ¿O debo declarar explícitamente una clase hash separada como segundo argumento de plantilla?

+1

La funcionalidad de hash se pasa como un parámetro de plantilla adicional. Necesitas (preferiblemente) un functor y haces 'unordered_set s (FooHasher());' – Xeo

Respuesta

8

Como una alternativa a la sugerencia de Xeo en los comentarios, puede proporcionar una especialización para std::hash antes de instanciar el unordered_set.

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

El parámetro foo a su método hash parece extraño a mí, pero implementa la especialización a la interfaz que ya ha proporcionado.

+0

Bien, gracias, eso funcionó. De hecho, no hice para que mi función hash tomara un parámetro adicional, es decir, un error tipográfico. Debe ser size_t hash() const {return x;} Lo único que me produce confusión es por qué no puedo hacer un hash() como lo hice con operator ==()? Para el operador == No tuve que hacer nada extra. – user1575106

+0

@ user1575106: diferentes API tendrán diferentes requisitos. Los escritores de estándares no pueden satisfacer el deseo de todos, y la interfaz dada hace que sea fácil probar diferentes algoritmos hash sin modificar la clase. – jxh

Cuestiones relacionadas