Hash function for user defined class. How to make friends? :)
Asked Answered
G

3

18

I have a class C, which has a string* ps private data member.
Now, I'd like to have an unordered_map<C, int> for which I need a custom hash function.

According to the c++ reference, I can do that like

namespace std {
  template<>
  class hash<C> {
  public:
    size_t operator()(const C &c) const
    {
      return std::hash<std::string>()(*c.ps);
    }
  };
}

The problem is that I can't seem to make operator() and C friends so that I could access ps.

I have tried this:

class C;
template<>
class std::hash<C>;
class C{
  //...
  friend std::hash<C>::operator ()(const C&) const; // error: Incomplete type 
};
// define hash<C> here.

but it says that Incomplete type ... in nested name specifier ...

I can't turn around the definitions either, because if class C is defined later, the hash<C> has no way to know about ps.

What am I doing wrong here? How can this situation be fixed without making ps public?

Greaser answered 15/12, 2012 at 8:49 Comment(0)
D
26

Try this:

class C;
namespace std {
  template<>
  struct hash<C> {
  public:
    size_t operator()(const C &c) const; // don't define yet
  };
}
class C{
  //...
  friend size_t std::hash<C>::operator ()(const C&) const;
};
namespace std {
  template<>
  size_t hash<C>::operator()(const C &c) const {
    return std::hash<std::string>()(*c.ps);
  }
}

Or this:

class C;
template<>
struct std::hash<C>;
class C{
  friend struct std::hash<C>; // friend the class, not the member function
};

(I haven't compiled so there might be a syntax error)

Dumanian answered 15/12, 2012 at 8:58 Comment(3)
yes, that's correct, thx, I'll mark it accepted in a sec. In the mean time I also figured out how silly I was! [embarrassed] :)Greaser
for msvc2012, you'll need to remove template<> in the implementation of the size_t hash<C>::operator(), otherwise error C2910 cannot be explicitly specialized.Jailbird
+1 for Jichao. On Gcc without removing template<>, I get error: template-id ‘operator()<>’ for ‘std::size_t std::hash<C>::operator()(const C&) const’ does not match any template declarationNoun
M
0

Simpler way to make friends:

class C {
  template <typename T> friend class std::hash;
};

This works even when C is in its own namespace or is a nested class, as std::hash won't have to be forward declared.

Mazarin answered 13/4, 2022 at 20:38 Comment(0)
P
-2

I'd suggest to add method like following

class C
{
....
public:  const string* get_ps() const { return ps; }
....
};

and use it in the your hash specialization.

Pop answered 11/1, 2013 at 19:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.