Untuk mendukung jenis kunci yang ditentukan pengguna std::unordered_set<Key>
dan std::unordered_map<Key, Value>
harus menyediakan operator==(Key, Key)
dan fungsi hash:
struct X { int id; /* ... */ };
bool operator==(X a, X b) { return a.id == b.id; }
struct MyHash {
size_t operator()(const X& x) const { return std::hash<int>()(x.id); }
};
std::unordered_set<X, MyHash> s;
Akan lebih mudah untuk menulis hanya std::unordered_set<X>
dengan hash default untuk tipe X
, seperti untuk tipe yang disertakan dengan kompilator dan pustaka. Setelah berkonsultasi
- C ++ Standard Draft N3242 §20.8.12 [unord.hash] dan §17.6.3.4 [hash.requirements],
- Boost.Unordered
- g ++
include\c++\4.7.0\bits\functional_hash.h
- VC10
include\xfunctional
- berbagai pertanyaan terkait di Stack Overflow
tampaknya mungkin untuk mengkhususkan std::hash<X>::operator()
:
namespace std { // argh!
template <>
inline size_t
hash<X>::operator()(const X& x) const { return hash<int>()(x.id); } // works for MS VC10, but not for g++
// or
// hash<X>::operator()(X x) const { return hash<int>()(x.id); } // works for g++ 4.7, but not for VC10
}
Mengingat dukungan compiler untuk C ++ 11 masih bersifat eksperimental --- Saya tidak mencoba Clang ---, ini adalah pertanyaan saya:
Apakah legal menambahkan spesialisasi seperti itu ke namespace
std
? Saya memiliki perasaan campur aduk tentang itu.std::hash<X>::operator()
Versi manakah , jika ada, yang sesuai dengan standar C ++ 11?Apakah ada cara portabel untuk melakukannya?
sumber
operator==(const Key, const Key)
std::hash
(tidak seperti hal lain dalamstd
namespace) tidak disarankan oleh panduan gaya Google ; ambillah dengan sebutir garam.Jawaban:
Anda secara tegas diizinkan dan didorong untuk menambahkan spesialisasi ke namespace
std
*. Cara yang benar (dan pada dasarnya hanya) untuk menambahkan fungsi hash adalah ini:(Spesialisasi populer lainnya yang mungkin Anda pertimbangkan untuk didukung adalah
std::less
,std::equal_to
danstd::swap
.)*) selama salah satu tipe yang terlibat ditentukan oleh pengguna, saya kira.
sumber
unorder_map<eltype, hash, equality>
, untuk menghindari merusak hari seseorang dengan bisnis ADL yang lucu. ( Edit nasihat Pete Becker tentang topik ini )operator==
.) Filosofi umum saya adalah jika fungsinya natural dan pada dasarnya satu-satunya yang "benar" (seperti perbandingan pasangan leksikografik), maka saya menambahkannya kestd
. Jika itu sesuatu yang aneh (seperti perbandingan pasangan tidak berurutan), maka saya membuatnya khusus untuk jenis wadah.Taruhan saya akan berada pada argumen template Hash untuk kelas unordered_map / unorder_set / ...:
Tentu saja
struct Xhasher { size_t operator(const X&) const; };
)std::hash<X>()
sumber
std::hash
masih merupakan jalan keluar terbaik :-)char*
!hash
spesialisasi mengganggu ADL? Maksud saya, ini sepenuhnya masuk akal, tetapi saya kesulitan untuk menemukan kasus masalah.std::unordered_map<Whatever, Xunset>
dan itu tidak berfungsi karenaXunset
jenis hasher Anda tidak dapat dibangun secara default.@Kerrek SB telah meliput 1) dan 3).
2) Meskipun g ++ dan VC10 mendeklarasikan
std::hash<T>::operator()
dengan tanda tangan berbeda, kedua implementasi library tersebut sesuai dengan Standar.Standar tidak menentukan anggota
std::hash<T>
. Ini hanya mengatakan bahwa setiap spesialisasi tersebut harus memenuhi persyaratan "Hash" yang sama yang diperlukan untuk argumen template keduastd::unordered_set
dan seterusnya. Yaitu:H
adalah objek fungsi, dengan setidaknya satu jenis argumenKey
.H
adalah salinan dapat dibangun.H
dapat dirusak.h
merupakan ekspresi tipeH
atauconst H
, dank
merupakan ekspresi tipe yang dapat diubah menjadi (mungkinconst
)Key
, makah(k)
ekspresi valid dengan tipesize_t
.h
merupakan ekspresi tipeH
atauconst H
, danu
merupakan nilai tipe lKey
, makah(u)
ekspresi valid dengan tipesize_t
yang tidak dimodifikasiu
.sumber
std::hash<X>::operator()
daripadastd::hash<X>
secara keseluruhan, dan tanda tangan daristd::hash<T>::operator()
adalah implementasi-didefinisikan.