gpt4 book ai didi

c++ - unordered_map/unordered_set 中元组的通用哈希

转载 作者:IT老高 更新时间:2023-10-28 12:53:36 25 4
gpt4 key购买 nike

为什么不 std::unordered_map<tuple<int, int>, string>只是开箱即用?必须为 tuple<int, int> 定义散列函数很繁琐。 ,例如

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

Building an unordered map with tuples as keys (Matthieu M.) 展示了如何为 boost::tuple 自动执行此操作.有没有在不使用可变参数模板的情况下对 c++0x 元组执行此操作?

这当然应该在标准中:(

最佳答案

这适用于 gcc 4.5,允许所有包含标准哈希类型的 c++0x 元组成为unordered_mapunordered_set 不用多说。(我将代码放在头文件中并包含它。)

函数必须存在于 std 命名空间中,以便被参数相关名称查找 (ADL)。

有没有更简单的解决方案?

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

};
}

标准符合代码

Yakk 指出,在 std 命名空间中专门化事物实际上是未定义的行为。如果您希望有一个符合标准的解决方案,那么您需要将所有这些代码移动到您自己的命名空间中,并放弃 ADL 自动找到正确哈希实现的任何想法。而不是:

unordered_set<tuple<double, int> > test_set;

你需要:

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

其中 hash_tuple 是您自己的命名空间,而不是 std::

为此,您首先必须在 hash_tuple 命名空间内声明一个哈希实现。这会将所有非元组类型转发到 std::hash:

namespace hash_tuple{

template <typename TT>
struct hash
{
size_t
operator()(TT const& tt) const
{
return std::hash<TT>()(tt);
}
};
}

确保 hash_combine 调用 hash_tuple::hash 而不是 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);
}
}

然后包含所有其他以前的代码,但将其放入 namespace hash_tuple 而不是 std::

namespace hash_tuple{

namespace
{
// 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;
}
};

}

关于c++ - unordered_map/unordered_set 中元组的通用哈希,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7110301/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com