首頁  >  文章  >  後端開發  >  如何在不編寫自訂雜湊函數的情況下使用元組作為無序映射中的鍵?

如何在不編寫自訂雜湊函數的情況下使用元組作為無序映射中的鍵?

Linda Hamilton
Linda Hamilton原創
2024-11-08 06:29:02717瀏覽

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

在沒有自訂雜湊函數的無序映射中使用元組

您可能期望std::unordered_map 能夠輕鬆地使用開箱即用的元組鍵。然而,它需要為元組定義一個雜湊函數,如下所示:

template<> struct do_hash<tuple<int, int>> {
    size_t operator()(std::tuple<int, int> const& tt) const {...}
};

這個過程可能會變得乏味,導致在不訴諸可變參數模板的情況下為C 0x 元組實現自動化的問題。

以下方法允許所有包含標準可雜湊類型的C 0x 元組成為unordered_map 和unordered_set 的一部分,而無需額外的努力:

#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;
        }
    };
}

透過將函數放置在std 命名空間中,可以透過參數存取它-依賴名稱查找(ADL)。

標準一致性代碼

專門化 std 命名空間中的物件是未定義的行為。因此,對於符合標準的解決方案,請將程式碼移至單獨的命名空間中並放棄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

在hash_tuple 命名空間中聲明一個哈希實現,以將所有非元組類型轉送到std: :hash 並修改hash_combine 以使用hash_tuple::hash 而不是std::hash。將剩餘的程式碼放在 hash_tuple 命名空間中。

要使用此解決方案,必須包含以下程式碼,這會放棄 ADL 的便利性:

unordered_set<tuple<double, int>, hash_tuple::hash<tuple<double, int>>> test2;

以上是如何在不編寫自訂雜湊函數的情況下使用元組作為無序映射中的鍵?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn