Rumah > Artikel > pembangunan bahagian belakang > Bagaimanakah anda boleh melaksanakan fungsi cincang generik untuk tupel dalam koleksi tidak tertib dalam C ?
Dalam bidang perpustakaan standard C, konsep tupel dan penggunaannya sebagai kunci dalam koleksi tidak tertib seperti std::unordered_map dan std::unordered_set boleh menimbulkan cabaran. Secara lalai, tupel tidak mempunyai fungsi cincang generik yang ditakrifkan, meninggalkan pembangun dengan tugas yang membosankan untuk menentukannya secara manual.
Mentakrifkan fungsi cincang tersuai untuk tupel boleh menjadi rumit dan terdedah kepada kesilapan. Untuk menangani isu ini, pembangun sering mencari penyelesaian yang lebih generik yang mengautomasikan proses.
Walaupun piawaian tidak menyediakan fungsi cincang generik secara eksplisit untuk tupel, piawaian -pendekatan patuh disediakan. Dengan mengalihkan kod ke ruang nama tersuai, adalah mungkin untuk mengelakkan tingkah laku tidak ditentukan yang dikaitkan dengan pengkhususan dalam ruang nama std.
Dalam pendekatan ini, ruang nama tersuai, hash_tuple, dicipta dengan pelaksanaan fungsi cincangnya sendiri . Pelaksanaan ini menghantar jenis bukan tuple ke fungsi std::hash.
namespace hash_tuple{ template <typename TT> struct hash { size_t operator()(TT const& tt) const { return std::hash<TT>()(tt); } }; }
Kod templat rekursif diubah suai untuk menggunakan hash_tuple::hash dan bukannya std::hash:
namespace hash_tuple{ namespace { template <class T> inline void hash_combine(std::size_t& seed, T const& v) { seed ^= hash_tuple::hash<T>()(v) + 0x9e3779b9 + (seed<<6) + (seed>>2); } } }
Akhir sekali, pengkhususan templat std diletakkan dalam ruang nama hash_tuple:
namespace hash_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; } }; }
Untuk menggunakan pendekatan ini, pengguna mesti menentukan ruang nama hash_tuple dalam pengisytiharan koleksi tidak tertib mereka:
unordered_set<tuple<double, int>, hash_tuple::hash<tuple<double, int>>> test2;
Walaupun penyelesaian ini mematuhi piawaian, ia memerlukan penentuan ruang nama untuk setiap pengisytiharan koleksi tidak tertib.
Pendekatan alternatif, yang tidak mematuhi piawaian C, ialah untuk meletakkan kod fungsi hash generik dalam ruang nama std. Ini membenarkan carian bergantung hujah (ADL) mencari pelaksanaan cincang yang betul secara automatik.
namespace std{ namespace { // Code from boost // Reciprocal of the golden ratio helps spread entropy // and handles duplicates. // See Mike Seymour in magic-numbers-in-boosthash-combine: // http://stackoverflow.com/questions/4948780 template <class T> inline void hash_combine(std::size_t& seed, T const& v) { seed ^= std::hash<T>()(v) + 0x9e3779b9 + (seed<<6) + (seed>>2); } // Recursive template code derived from Matthieu M. 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 pendekatan ini, sintaks koleksi tidak tertib kekal lebih mudah:
unordered_set<tuple<double, int> > test_set;
Walau bagaimanapun, teknik ini membawa risiko tingkah laku yang tidak ditentukan disebabkan oleh pengkhususan dalam ruang nama std.
Pencincangan generik tupel dalam koleksi tidak tertib ialah masalah bukan remeh yang memerlukan pelaksanaan tersuai. Kedua-dua pendekatan yang mematuhi piawaian dan tidak standard yang digariskan dalam artikel ini memberikan penyelesaian yang berdaya maju. Akhirnya, pilihan antara pendekatan ini bergantung pada keperluan pembangun dan toleransi terhadap potensi tingkah laku yang tidak ditentukan.
Atas ialah kandungan terperinci Bagaimanakah anda boleh melaksanakan fungsi cincang generik untuk tupel dalam koleksi tidak tertib dalam C ?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!