2012-01-01 15 views
10

próbuję wykonać następujące czynności:Jak dokonać doładowania unordered_map wspierać muszej <string>

boost::unordered_map<boost::flyweight<std::string>, boost::flyweight<std::string> > map; 

     boost::flyweight<std::string> foo(name); 
     map[foo] = foo; 

Ale kompilator narzeka: „błąd C2665:«boost :: hash_value»: żaden z 17 przeciążeń może przekonwertuj wszystkie typy argumentów ".

Ale zdefiniowano następujące funkcje:

std::size_t hash_value(const boost::flyweight<std::string> & b) 
{ 
    boost::hash<std::string> hasher; 
    const std::string & str = b.get(); 
    return hasher(str); 
} 
bool operator==(const boost::flyweight<std::string>& f, const boost::flyweight<std::string> & second) 
{ 
    return f.get() == second.get(); 
} 

Ale to doesnt skompilować.

Co muszę zrobić, aby wzmocnić unordered_map, aby obsługiwać muszkę?

[EDIT] Dostałem go do pracy z następującego kodu:

struct flyweight_hash 
    { 
     std::size_t operator()(const boost::flyweight<std::string> &elm) const 
     { 
      boost::hash<std::string> hasher; 
      const std::string & str = elm.get(); 
      return hasher(str); 
     } 
    }; 

i przekazał go jako parametr szablonu do budowy mapy:

boost::unordered_map<boost::flyweight<std::string>, boost::flyweight<std::string> , flyweight_hash > map; 

W tym przypadku nie rozumiem, jak przeciążanie hash_value nie zadziałało.

Odpowiedz

7

boost::hash połączenia hash_value poprzez wyszukiwanie zależne od argumentu (ADL). Próbujesz zdefiniować funkcję hash_value dla klasy w przestrzeni nazw boost. W związku z tym twoja funkcja hash_value musiałaby również wejść w tę przestrzeń nazw, aby narzędzie ADL działało. Niestety dodanie funkcji do obcego obszaru nazw jest raczej złe i należy tego unikać. Twoje rozwiązanie używania niestandardowego hausa wydaje się być w porządku.

Trochę przykładowy kod do zilustrowania:

namespace boost { 
    // somewhere in boost 
    template<typename T> 
    std::size_t hash(const T& t) { 
    // call using ADL 
    // e.g. if called with object of class type foo::bar this will 
    // pick up foo::hash_value despite the lack of namespace 
    // qualification 
    return hash_value(t); 
    } 
} 

// your hash_value (presumably in the global namespace) 
// not picked up by above call 
std::size_t hash_value(boost::flyweight<T>...); 

namespace boost { 
    // this would be picked up but is slightly evil 
    std::size_t hash_value(boost::flyweight<T>...); 
} 
+0

Jest tylko zły, ponieważ domyślny haszownik 'boost :: unordered_map' nie wydaje się wywoływać ADL przez' using boost :: hash_value; return hash_value (klucz); '. Nie mogę tego teraz sprawdzić. – Xeo

+0

@Xeo Domyślny hasz powinien być 'boost :: hash' i nie powinien być specyficzny dla' unordered_map'. Przynajmniej doktor tak mówi. – pmr

+0

Oczywiście, ale to nie zmienia faktu, że połączenia obsługujące ADL nie wydają się być używane. – Xeo

5

Szkoda hash coś, co zostało już zakodowanej. Flyweight utrzymuje pojedynczą instancję równych obiektów, więc skuteczniej jest zaszyfrować adres tej instancji, a nie jej zawartość. Zrobić w następujący sposób (w std, a nie w boost, jak używam C++ 11, więc mam rozszerzenie std::hash, nie boost::hash):

namespace std 
{ 
    template <typename T> 
    struct hash<boost::flyweight<T, boost::flyweights::no_tracking>> 
    { 
    using value_type = boost::flyweight<T, boost::flyweights::no_tracking>; 
    size_t operator()(const value_type& ss) const 
    { 
     hash<const void*> hasher; 
     return hasher(&ss.get()); 
    } 
    }; 
} 

I zostały potwierdzone, że to działa na zasadzie projektu, nie przez przypadek: http://lists.boost.org/boost-users/2013/03/78007.php