Rumah >pembangunan bahagian belakang >C++ >Bagaimanakah saya boleh menggunakan tupel sebagai kunci dalam peta tidak tersusun tanpa menulis fungsi cincang tersuai?

Bagaimanakah saya boleh menggunakan tupel sebagai kunci dalam peta tidak tersusun tanpa menulis fungsi cincang tersuai?

Linda Hamilton
Linda Hamiltonasal
2024-11-08 06:29:02753semak imbas

How can I use tuples as keys in unordered maps without writing a custom hash function?

Menggunakan Tuple dalam Peta Tidak Tertib Tanpa 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).

Kod Pematuhan Standard

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!

Kenyataan:
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