Rumah >pembangunan bahagian belakang >C++ >Bagaimanakah saya boleh menggunakan tupel sebagai kunci dalam peta tidak tersusun tanpa menulis fungsi cincang tersuai?
Anda mungkin menjangkakan std::unordered_map berfungsi dengan mudah dengan kunci tuple di luar kotak. Walau bagaimanapun, ia memerlukan penentuan fungsi cincang untuk tupel, seperti yang ditunjukkan di bawah:
template<> struct do_hash<tuple<int, int>> { size_t operator()(std::tuple<int, int> const& tt) const {...} };
Proses ini boleh menjadi membosankan, membawa kepada persoalan mengautomasikannya untuk tupel C 0x tanpa menggunakan templat variadic.
Pendekatan berikut membenarkan semua tuple C 0x yang mengandungi jenis hashable standard menjadi sebahagian daripada unordered_map dan unordered_set tanpa usaha tambahan:
#include <tuple> namespace std { namespace { template <class T> inline void hash_combine(std::size_t& seed, T const& v) { // Modified from Boost seed ^= std::hash<T>()(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2); } // Recursive template for hashing tuples template <class Tuple, size_t Index = std::tuple_size<Tuple>::value - 1> struct HashValueImpl { static void apply(size_t& seed, Tuple const& tuple) { HashValueImpl<Tuple, Index - 1>::apply(seed, tuple); hash_combine(seed, std::get<Index>(tuple)); } }; template <class Tuple> struct HashValueImpl<Tuple, 0> { static void apply(size_t& seed, Tuple const& tuple) { hash_combine(seed, std::get<0>(tuple)); } }; } template <typename... TT> struct hash<std::tuple<TT...>> { size_t operator()(std::tuple<TT...> const& tt) const { size_t seed = 0; HashValueImpl<std::tuple<TT...>>::apply(seed, tt); return seed; } }; }
Dengan meletakkan fungsi dalam ruang nama std, ia boleh diakses melalui pencarian nama bergantung kepada argumen (ADL).
Pengkhususan objek dalam ruang nama std ialah tingkah laku yang tidak ditentukan. Oleh itu, untuk penyelesaian yang mematuhi piawaian, alihkan kod ke ruang nama yang berasingan dan tinggalkan kemudahan ADL:
namespace hash_tuple { // Forward non-tuple types to std::hash template <class TT> struct hash { size_t operator()(TT const& tt) const { return std::hash<TT>()(tt); } }; // Hash function combining values in a tuple template <class Tuple, size_t Index = std::tuple_size<Tuple>::value - 1> struct HashValueImpl { static void apply(size_t& seed, Tuple const& tuple) { HashValueImpl<Tuple, Index - 1>::apply(seed, tuple); hash_combine(seed, std::get<Index>(tuple)); } }; template <class Tuple> struct HashValueImpl<Tuple, 0> { static void apply(size_t& seed, Tuple const& tuple) { hash_combine(seed, std::get<0>(tuple)); } }; // Hash function for tuples template <typename... TT> struct hash<std::tuple<TT...>> { size_t operator()(std::tuple<TT...> const& tt) const { size_t seed = 0; HashValueImpl<std::tuple<TT...>>::apply(seed, tt); return seed; } }; } // namespace hash_tuple
Isytiharkan pelaksanaan cincang dalam ruang nama hash_tuple untuk memajukan semua jenis bukan tuple ke std: :hash dan ubah suai hash_combine untuk menggunakan hash_tuple::hash dan bukannya std::hash. Letakkan kod yang tinggal di dalam ruang nama hash_tuple.
Untuk menggunakan penyelesaian ini, anda mesti menyertakan kod berikut, yang mengabaikan kemudahan ADL:
unordered_set<tuple<double, int>, hash_tuple::hash<tuple<double, int>>> test2;
Atas ialah kandungan terperinci Bagaimanakah saya boleh menggunakan tupel sebagai kunci dalam peta tidak tersusun tanpa menulis fungsi cincang tersuai?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!