首页 > 后端开发 > C++ > 如何在不编写自定义哈希函数的情况下使用元组作为无序映射中的键?

如何在不编写自定义哈希函数的情况下使用元组作为无序映射中的键?

Linda Hamilton
发布: 2024-11-08 06:29:02
原创
751 人浏览过

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中文网其他相关文章!

来源:php.cn
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板