2012-08-03 14 views
5

Muszę użyć unordered_set dla raczej dużego projektu i aby upewnić się, że używam go poprawnie, spróbowałem małego przykładu.Zgłaszanie funkcji mieszania dla unordered_set w 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; 
} 

Kiedy skompilować uzyskać:

/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 

Wydaje się, że to nie widząc mój funkcji skrótu, ale pomyślałem: „hash” była domyślna nazwa funkcji. Czy poprawnie zdefiniowałem hash? Czy muszę jawnie zadeklarować oddzielną klasę haszu jako drugi argument szablonu?

+1

Funkcja mieszania jest przekazywana jako dodatkowy parametr szablonu. Potrzebujesz (najlepiej) funktora i wykonaj polecenie 'unordered_set s (FooHasher());' – Xeo

Odpowiedz

8

Jako alternatywę dla sugestii Xeo w komentarzach, możesz utworzyć specjalizację dla std::hash przed utworzeniem instancji unordered_set.

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

parametr do metody hashfoo wydaje mi obce, ale realizowane specjalizacji do interfejsu, który podałeś.

+0

OK, dzięki, zadziałało. Naprawdę nie dla mojej funkcji skrótu, aby wziąć dodatkowy parametr, to jest literówka. Powinno to być size_t hash() const {return x;} Jedyna rzecz, na którą się nie znam, to dlaczego nie mogę po prostu utworzyć skrótu(), tak jak zrobiłem to z operatorem ==()? Dla operatora == nie musiałem robić nic więcej. – user1575106

+0

@ user1575106: Różne interfejsy API będą miały różne wymagania. Twórcy standardów nie są w stanie zaspokoić wszystkich potrzeb, a dany interfejs ułatwia wypróbowanie różnych algorytmów mieszania bez modyfikowania klasy. – jxh