Rumah > pembangunan bahagian belakang > C++ > Bagaimanakah anda boleh melaksanakan fungsi cincang generik untuk tupel dalam koleksi tidak tertib dalam C ?

Bagaimanakah anda boleh melaksanakan fungsi cincang generik untuk tupel dalam koleksi tidak tertib dalam C ?

DDD
Lepaskan: 2024-11-06 21:20:02
asal
842 orang telah melayarinya

How can you implement a generic hash function for tuples in unordered collections in C  ?

Pencincangan Generik untuk Tuple dalam Koleksi Tidak Tertib

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.

Keperluan untuk Penyelesaian Generik

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.

Pendekatan Mematuhi Piawaian

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&amp; tt) const
    {                                              
        return std::hash<TT>()(tt);                                 
    }                                              
};
}
Salin selepas log masuk

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&amp; seed, T const&amp; v)
        {
            seed ^= hash_tuple::hash<T>()(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
        }
    }
}
Salin selepas log masuk

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&amp; tt) const
        {                                              
            size_t seed = 0;                             
            HashValueImpl<std::tuple<TT...> >::apply(seed, tt);    
            return seed;                                 
        }                                              
    };
}
Salin selepas log masuk

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;
Salin selepas log masuk

Walaupun penyelesaian ini mematuhi piawaian, ia memerlukan penentuan ruang nama untuk setiap pengisytiharan koleksi tidak tertib.

Pendekatan Bukan Standard

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&amp; seed, T const&amp; 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&amp; seed, Tuple const&amp; 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&amp; seed, Tuple const&amp; tuple)
          {
            hash_combine(seed, std::get<0>(tuple));
          }
        };
    }

    template <typename ... TT>
    struct hash<std::tuple<TT...>> 
    {
        size_t
        operator()(std::tuple<TT...> const&amp; tt) const
        {                                              
            size_t seed = 0;                             
            HashValueImpl<std::tuple<TT...> >::apply(seed, tt);    
            return seed;                                 
        }                                              

    };
}
Salin selepas log masuk

Dengan pendekatan ini, sintaks koleksi tidak tertib kekal lebih mudah:

unordered_set<tuple<double, int> > test_set;
Salin selepas log masuk

Walau bagaimanapun, teknik ini membawa risiko tingkah laku yang tidak ditentukan disebabkan oleh pengkhususan dalam ruang nama std.

Kesimpulan

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!

sumber:php.cn
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan