Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Specializing std::hash for private member class

I have a class (call it Outer) which has a private member class (Inner). I want to store instances of Outer::Inner in unordered standard containers, so I want to specialize std::hash<Outer::Inner>.

However, when writing this:

namespace std {
    template<>
    struct hash<Outer::Inner> {
        std::size_t operator()(const Outer::Inner &arg) const
        {
            return std::hash<int>()(arg.someSpecialProperty);
        }
    };
}

the compiler complains:

error: 'Inner' is a private member of 'Outer'
            std::size_t operator()(const Outer::Inner &p) const
                                                ^

I have tried to make std::hash a friend struct by following this answer, but that didn't work either: the forward declaration of Outer::Inner failed with:

error: use of undeclared identifier 'Outer'

So how should I proceed (if what I intend to do is possible at all)?

like image 710
The Paramagnetic Croissant Avatar asked Dec 11 '22 06:12

The Paramagnetic Croissant


2 Answers

Got it ! The solution is to use your own functors, not specialize std::hash.

struct A
{
  A() { v.insert(std::make_pair(B(1), 6)); }

private:
  struct B
  {
    B(int i = 0) : m_i(i) { }

    int m_i;
  };

  struct HashB { std::size_t operator()(const B& b) const { return b.m_i; } };
  struct EqualB { bool operator()(const B&b1, const B&b2) const { return b1.m_i == b2.m_i; } };


  std::unordered_map<B, int, HashB, EqualB> v;
};
like image 180
AntiClimacus Avatar answered Dec 21 '22 13:12

AntiClimacus


Since it's a private inner type, I assume that you have a private or protected std::unordered_map member in the enclosing class. If that's the case, just write a private inner hash functor and pass it as the third argument of the std::unordered_map. It's the easiest solution to your problem, I think.

like image 22
Manu343726 Avatar answered Dec 21 '22 12:12

Manu343726