【问题标题】:My std::hash for std::tuples... Any improvements? [closed]我的 std::hash for std::tuples ...有什么改进吗? [关闭]
【发布时间】:2013-02-27 04:02:07
【问题描述】:

有些人可能已经注意到 std::hash 不支持元组。所以我添加了一个看起来比我到目前为止看到的解决方案“更好”的重载。任何人有想法进一步减少此代码?请注意,这是一个编译器杀手!唯一可以编译它的是“Clang 3.2”......英特尔编译器 13.1 没有获得专业化并一直告诉“C++ 标准不支持哈希 blabla”。而且我们不需要谈论原始的 Microsoft 编译器吧。

顺便说一句,我的解决方案支持像 std::tuple<std::tuple<int,int>,int> 这样的递归元组,所以我不确定这是否也适用于我今天看到的现有解决方案。

namespace std
{
    template<typename... TTypes>
    class hash<std::tuple<TTypes...>>
    {
    private:
        typedef std::tuple<TTypes...> Tuple;

        template<int N>
        size_t operator()(Tuple value) const { return 0; }

        template<int N, typename THead, typename... TTail>
        size_t operator()(Tuple value) const
        {
            constexpr int Index = N - sizeof...(TTail) - 1;
            return hash<THead>()(std::get<Index>(value)) ^ operator()<N, TTail...>(value);
        }

    public:
        size_t operator()(Tuple value) const
        {
            return operator()<sizeof...(TTypes), TTypes...>(value);
        }
    };
}

【问题讨论】:

  • gcc 可以编译这个(至少 gcc 4.7)
  • 从技术上讲,我认为您实际上是在使用参数 template 声明一个新模板,而不是使用参数 template...专门化现有模板...这在技术上是不合法的据我了解,为 C++03 中的标准模板做...所以如果你将它留在 std 命名空间中,这可能是不符合标准的...我不确定在 C+ 中是否仍然如此+11 虽然
  • @thesaint,异或不是组合哈希值的好方法
  • @JonathanWakely:这是一个非常无用的声明。如果有任何原因,请提供有关原因的链接以及您会推荐的内容。此外,XOR 是稳定的。如果您使用良好的散列函数,例如 SHA-160 的前 64 位,那么 XOR 是混合散列值的完美方法。因此,您的评论绝对值得详细说明...对于通常的“愚蠢”哈希函数,在 XORing 之前向左旋转大约“Index * 13”位左右可能是更好的选择。
  • @thesaint,只是 XOR 不是一个好的哈希函数,因为例如 {1,2,3,4} 与 {4,3,2,1} 碰撞

标签: c++ templates c++11 variadic-templates stdhash


【解决方案1】:

看过之后就很明显了:

template<int N, typename THead, typename... TTail>
size_t operator()(Tuple value) const
{
  constexpr int Index = N - sizeof...(TTail) - 1;
  return hash<THead>()(std::get<Index>(value)) ^ operator()<N, TTail...>(value);
}

【讨论】:

  • 大声笑,是的,谢谢.. 如果您“烹饪”解决方案直到它起作用,就会发生这种情况。我上面已经应用了!
  • 另外一个:你应该把参数设为const Tuple&amp; value,而不是一直在三个地方都创建副本。
  • 这取决于。但在这种情况下,它可能也不会受到伤害。 C++11 有新的习惯用法,避免使用“const&”,而是使用“pass-by-value”。嗯移动语义。大声笑我不知道为什么了。移动语义似乎也不能真正解决这个问题。好像是一个组合。 RValues 的移动语义和 LValues 的编译器内部优化。对我来说,使用“const&”似乎是一种过早的优化,除非你需要继承。
  • 不,当您的函数相互调用时,您的上述代码 (Tuple value) 不会移动任何内容。它创建副本。你唯一的希望是优化器,我不会依赖它。
  • 上面是一个对称哈希,也就是说make_tuple( 0, 0 )make_tuple( 1, 1 )都有一个0的哈希。其次,将hash 特化为stdstd::tuple&lt; Ts... &gt; 是未定义的行为,因为您只能将templates 特化为namespace std 用于用户定义类型或依赖于用户定义类型的类型。
猜你喜欢
  • 1970-01-01
  • 2021-12-31
  • 2017-01-16
  • 2013-08-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-10
  • 1970-01-01
相关资源
最近更新 更多