Is there something terribly wrong with this implementation?
template <class T>
constexpr inline std::size_t hash_combine(T const& v,
std::size_t const seed = {}) noexcept
{
return seed ^ (std::hash<T>()(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2));
}
template <typename T> struct hash;
template <typename ...T>
struct hash<std::tuple<T...>>
{
template <typename A1, typename ...A, std::size_t ...I>
static auto apply_tuple(std::tuple<A1, A...> const& t,
std::index_sequence<I...>) noexcept
{
if constexpr(sizeof...(A))
{
return hash_combine(std::get<0>(t),
hash<std::tuple<A const&...>>()({std::get<I + 1>(t)...})
);
}
else
{
return std::hash<std::remove_cv_t<std::remove_reference_t<A1>>>()(
std::get<0>(t));
}
}
auto operator()(std::tuple<T...> const& t) const noexcept
{
return apply_tuple(t,
std::make_index_sequence<sizeof...(T) - 1>()
);
}
};
EDIT: This is better, I think:
template <typename ...T>
struct hash<std::tuple<T...>>
{
template <std::size_t ...I>
static auto apply_tuple(std::tuple<T...> const& t,
std::index_sequence<I...>)
{
std::size_t seed{};
return ((seed = hash_combine(std::get<I>(t), seed)), ...);
}
auto operator()(std::tuple<T...> const& t) const
{
return apply_tuple(t, std::make_index_sequence<sizeof...(T)>());
}
};