As an exercise I was trying to see if I could use SFINAE to create a std::hash
specialization for std::pair
and std::tuple
when all of its template parameters are of an unsigned type. I have a little experience with them, but from what I understand the hash function needs to have already been templated with a typename Enabled = void
for me to add a specialization. I'm not really sure where to go from here. Here's an attempt which doesn't work.
#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;
}
Error:
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>>
It's about what I expected because I'm trying to extend the template parameters to hash... But I'm not sure the technique to handle these cases then. Can someone help me understand?
You are not supposed to specialize std::hash
for types that doesn't depend on a type you defined yourself.
That said, this hack might work:
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;
}
};
Really, though, don't do this. Write your own hasher.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With