C++ std::tr1::hash for a templated class
Asked Answered
G

1

5

I have this templated class:

template <typename T> Thing { ... };

and I would like to use it in an unordered_set:

template <typename T> class Bozo {
  typedef unordered_set<Thing<T> > things_type;
  things_type things;
  ...
};

Now class Thing has everything it needs except a hash function. I would like to make this generic so I try something like:

namespace std { namespace tr1 {
  template <typename T> size_t hash<Thing<T> >::operator()(const Thing<T> &t) const { ... }
}}

Attempts to compile this with g++ 4.7 have it screaming

expected initializer before ‘<’

about the

hash<Thing<T> >

part of the declaration. Any clues will help save the few remaining hairs on my head.

Gayomart answered 8/5, 2013 at 22:20 Comment(0)
S
7

You cannot provide a specialization for just hash::operator()(const T&); just specialize the entire struct hash.

template<typename T>
struct Thing {};

namespace std { namespace tr1 {
    template<typename T>
    struct hash<Thing<T>>
    {
        size_t operator()( Thing<T> const& )
        {
            return 42;
        }
    };
}}

Another way to do this is to create a hasher for Thing, and specify this as the second template argument for the unordered_set.

template<typename T>
struct Thing_hasher
{
  size_t operator()( Thing<T>& const )
  {
    return 42;
  }
};

typedef std::unordered_set<Thing<T>, Thing_hasher<T>> things_type;
Serbocroatian answered 8/5, 2013 at 22:34 Comment(3)
I believe this is one of the rare cases where you may write inside the std namespace :-)Hadwin
@Hadwin Yes, you are allowed to add specializations to the std namespaceSerbocroatian
Sadly for me only the second option will work. It is probably the case that the first will work under C++-11 but my application has to go both ways. The first option produces conflicts with existing definitions of hash<T> pre-C++-11. Many thanks all the same.Gayomart

© 2022 - 2024 — McMap. All rights reserved.