0

I am trying to make one of my classes hash-able and saw this: How to specialize std::hash<Key>::operator() for user-defined type in unordered containers?

namespace std {
  template <> struct hash<Foo>
  {
    size_t operator()(const Foo & x) const
    {
      /* your code here, e.g. "return hash<int>()(x.value);" */
    }
  };
}

With the above code, everything works fine. But I am trying to understand the mechanism better.

Why do we have to add an extra pair of parentheses in the middle of hash<int>()(...)? It looks ugly. Why can't we design it so that it is just hash<int>(...)?

Community
  • 1
  • 1
Yuchen
  • 30,852
  • 26
  • 164
  • 234

1 Answers1

3

Why do we have to add an extra pair of parentheses in the middle of hash<int>()(...)?

The hash<int> is a class, hence it needs an instance of the class before the call operator can be applied, hence;

hash<int>()

For the instance, and;

hash<int>()(...) 

To call it.

Why can't we design it so that it is just hash<int>(...)?

Several reasons, most notable is that you can partially specialise class templates; you can only fully specialise function templates.

It is also idiomatic, there are many standard library algorithms and containers that expect types that behave like functions, but may not always be functions. Functor use allows for that.

Niall
  • 30,036
  • 10
  • 99
  • 142
  • So in short, it's yet another giant abstraction leak from C++'s muddled and rigid syntax, resulting in inexpressive and non-obvious weirdness. – Lightness Races in Orbit Apr 25 '16 at 20:56
  • Lol. When used without a named instance (eg like the temporary in the sample), it does look cumbersome. – Niall Apr 25 '16 at 20:59
  • 2
    Y'know, while I will always have a certain affinity for C++, and I certainly understand _why_ it is the way it is (and why in some ways that's not even a bad thing), I'm feeling more and more critical of it as time goes on. Life's too short, I guess. – Lightness Races in Orbit Apr 25 '16 at 21:00