2015-04-30 12 views
16

Z typem regularnym, mam na myśli definicję Stepanov w Elementy programowania, w zasadzie, że istnieje koncepcja równości i że obiekty, które są kopie siebie nawzajem porównać równe.C++ 11: Czy istnieją powody, dla których niektóre typy regularne nie powinny mieć specjalizacji `std :: hash`?

Więc kiedy masz Regularne Rodzaj T oraz relacja równości jest przechodnia (a == b & & b == c => a == c), można zdefiniować (nietrywialne) funkcja skrótu zgodna z definicją równości (a == b => h (a) == h (b)). Zawsze.

Jednak standard nie obejmuje wielu specjalizacji std::hash. Na przykład. std::complex nie ma, ani nie ma kontenerów, z godnymi wyjątkami vector<bool> i bitset.

Zastanawiam się, jaka jest tutaj zasada projektowania.

Lub zapytano inaczej: czy istnieją powody, dla których nie należy udzielać specjalizacji std::hash dla własnych typów, o ile są one regularne, a równość jest przechodnią?

+1

Oczywiście, zawsze można zdefiniować funkcję skrótu, która jest spójna: 'size_t operator() (T & const) const {return 0; } 'Pytanie brzmi, czy zawsze możesz zdefiniować taki, który jest dobry dla dowolnego typu? – Barry

+0

'wektor ' nie jest zaimplementowany jako 'wektor'' bool's. Jest to szablon specjalizacji, która polega na 'int', aby zapisać kilka' bool's (zakładam 32). Jest niezmiennikiem wszystkich parametrów szablonu (i bazowych typów '' std :: hash'), dlatego właśnie specjalizacja jest zapewniona. – mike

+0

Istnieje wiele typów w standardowej bibliotece, które mają [stałe żądania otwarte] (https://cplusplus.github.io/LWG/lwg-active.html#1025), aby specjalizować 'std :: hash' – CoryKramer

Odpowiedz

0

Zapewnienie specjalizacji dla własnych typów nie ma sensu, jeśli są to klasy szablonów, , ponieważ funkcja hash (z wysokim bardzo wysokim prawdopodobieństwem) zależy również od nieznanych typów parametrów szablonu szablonu .

To nie istnieją żadne parametry szablonu lub parametry szablonu są ograniczone do pewnych typów

// provide no implementation to restrict all types 
template<typename T> container; 

// int is allowed 
template<> container<int> { 
    ... 
} 

// double is allowed 
template<> container<double> { 
    ... 
} 

zapewniając specjalizacja std::hash jest możliwe, ponieważ implementacje klas (lub się instancja klasy szablonu) są znane , jak to jest w przypadku vector<bool> w przeciwieństwie do complex<T>.

+0

Co jest nie tak z 'namespace std {template struct hash > {using result_type = size_t; using argument_type = complex ; operator result_type() (const argument_type & a) const {std :: hash hash; size_t result = hash (a.real()) + 0x9e3779b9; wynik^= hash (a.imag()) + 0x9e3779b9 + (wynik << 6) + (wynik >> 2); wynik zwrotu; }}; } '? –

+0

Tutaj sformatowana wersja: http://pastebin.com/CcwKmEMy – mike

+0

wiersz 'std :: hash hash;' wymaga specjalności 'std :: hash' dla' T', używa tej specjalizacji do tworzenia specjalizacja dla "kompleksu ", ale skąd wiadomo, że przyniesie to skuteczną implementację? – mike

2

Tak.

Gdy typ ma dwie następujące właściwości nie sądzę, należy zdefiniować std::hash:

  • Nie ma skuteczny sposób konsekwentnie tworzyć wysokiej jakości mieszania, który obejmuje wszystkie dane używane do opisania równości .

  • Nie ma wydajnego i/lub intuicyjnego sposobu wyboru spójnego podzbioru danych do wartości mieszania.

+0

W rzeczywistości 'std :: hash ' może być zaimplementowany w * czasie liniowym *, podczas gdy 'operator ==' ma najgorszy czas rzucania * czas kwadratowy *. Po prostu mieszaj poszczególne elementy i używaj komutacyjnego sumatora mieszającego (niepodpisane dodawanie, * nie * xor). –

+0

@ MarcMutz-mmutz Nieważne mój pierwszy komentarz - jeśli funkcja hash tworzy jednolite wartości, dodawanie jest w porządku. Zobaczę, czy mogę znaleźć lepszy przykładowy typ - myślę, że moje właściwości są jednak dobre. – orlp

Powiązane problemy