使用SFINAE进行std::hash特化?

9
作为一项练习,我试图使用SFINAE(Substitution Failure Is Not An Error)来创建一个std::pair和std::tuple的std::hash特化版本,当它们所有的模板参数都是无符号类型时。虽然我对它们有一点经验,但据我所知,哈希函数需要已经使用typename Enabled = void进行了模板化,以便我添加一个特化版本。我不太确定接下来该怎么做。这里是一个不起作用的尝试。
#include <functional>
#include <type_traits>
#include <unordered_set>
#include <utility>

namespace std {
template <typename T, typename Enabled = void>
struct hash<std::pair<T, T>, std::enable_if_t<std::is_unsigned<T>::value>>
{
    size_t operator()(const std::pair<T, T>& x) const
    {
        return x;
    }
};
}; // namespace std


int
main(int argc, char ** argv)
{
    std::unordered_set<std::pair<unsigned, unsigned>> test{};
    return 0;
}

错误:

hash_sfinae.cpp:7:42: error: default template argument in a class template partial specialization
template <typename T, typename Enabled = void>
                              ^
hash_sfinae.cpp:8:8: error: too many template arguments for class template 'hash'
struct hash<std::pair<T, T>, std::enable_if_t<std::is_unsigned<T>::value>>

我的预期是扩展模板参数到哈希,所以这个情况很正常。但我不确定如何处理这些情况的技术方法。有人可以帮我理解吗?

1个回答

13

您不应该为与您自己定义的类型无关的类型专门化std::hash

话虽如此,这个技巧可能有效:

template<class T, class E>
using first = T;

template <typename T>
struct hash<first<std::pair<T, T>, std::enable_if_t<std::is_unsigned<T>::value>>>
{
    size_t operator()(const std::pair<T, T>& x) const
    {
        return x;
    }
};

但实际上,不建议这样做。最好自己编写哈希函数。


有一个很好的理由不为pair/tuple专门定制std::hash:我真的希望自动组合哈希很快会出现在std中。 - Yakk - Adam Nevraumont
为什么这里需要 first?也就是说,为什么不使用 std::enable_if_t<std::is_unsigned<T>::value, T>enable_if 不是应该做 first 在这里的工作吗? - ofo
很遗憾,这在clang上不起作用 https://godbolt.org/z/qjTMEvbse - dmayola

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接