3

I have tried to implement a std::hash function which works on any iterator type, where the user has to implement a hashing function for their type T. My initial implementation of the std::hash function for std::array be seen below:

template <typename T, size_t N>
struct std::hash<std::array<T, N>> {
    std::size_t operator()(const std::array<T, N>& x) const {
        auto hash_func = std::hash<T>{};
        size_t h_val{};
        for (T t : x) {
            h_val = h_val ^ hash_func(t);
        }
        return h_val;
    }
};

For supporting any iterator I have been trying to use sfinae, where my current implementation of a container type is_container can be seen below:

template <typename T, typename = void> // primary declaration
struct is_container: std::false_type {}; // when all specializations fail

template <typename T>
struct is_container< // specialization
        T, // conditions:
        std::void_t<decltype(std::begin(std::declval<T&>()))>
>: std::true_type {};

template <typename C>  // *_v value
constexpr auto is_container_v = is_container<C>::value;

My problem is that I can't seem to match the required parameters for the struct std::hash<>.

Jakobo06
  • 65
  • 5
  • 2
    Do note that adding a specialization to `std::hash` for the the library types is UB. You are only allowed to specialize for you own types. I would just write your own hash functor that will work with any iterable type and give that to the things that need it. – NathanOliver Jun 06 '19 at 21:59
  • 1
    Can't say off the top of my head how you could use `is_container` to conditionally enable a `std::hash` specialisation, but a couple things that you may or may not realise: `for (T t : x)` deep-copies all the elements - prefer `for (const T& t : x)`, and `h_val = h_val ^ hash_func(t);` is *the* classic example of collision prone hashing for multiple values - check out [boost `hash_combine`](https://stackoverflow.com/q/35985960/410767). – Tony Delroy Jun 06 '19 at 22:50

0 Answers0