2

I'm practice building a hashtable that can accept different types using template.

How do I implement hashFunction not knowing the types at compile time?

template<class K, class V>
class HashTable {
  public:
  vector<vector<Bucket<K, V> > > table;
  ...
  size_t hashFunction(const K &k) {
    //can't implement without knowing the runtime types
  }
}

I'm guessing I should do something similar like:

return hash<K>(k) % table.size();

Update:

Thanks for R Sahu's answer, now I know it's the Template Partial Specialization part that I wasn't clear of. See this question and this link for reference.

Community
  • 1
  • 1
not_too_shabby
  • 84
  • 1
  • 11
  • I think you (or, at least, the compiler) *do* know the types at *compile*-time. Unless you have a way to look up the size of a type at run-time given its `typeid`, there is not much you can do. Note that the compiler knows exactly what type `K` is for each instantiation of `HashTable`. – 5gon12eder Jan 04 '16 at 03:17

1 Answers1

3

How do I implement hashFunction not knowing the types at compile time?

You can have generic logic that can be used generate a hash value for all types. Treat the bytes that make up k like the characters in a string.

Also, provide the ability for the user to provide their own hash functions.

// Generic implementation
template <typename K> struct Hash
{
   static size_t get(const K& k)
   {
      ...
   }
};

template<class K, class V, typename HashGenerator = Hash<K>>
class HashTable {
  public:
  vector<vector<Bucket<K, V> > > table;
  ...
  size_t hashFunction(const K &k) {
     HashGenerator::get(k);
  }
}

struct Foo { ... };

// Specialize Hash for Foo.
template <> struct Hash<Foo>
{
   static size_t get(const Foo& foo)
   {
      ...
   }
}
R Sahu
  • 196,807
  • 13
  • 136
  • 247
  • Thanks for the quick reply. I assume `HashGenerator` is just an alias for `Hash`, Simply `class Hash` also works. – not_too_shabby Jan 02 '16 at 08:20
  • @LihsingChen, using `HashGenerator` as a default parameter allows you to use a completely different class that is unrelated to `Hash` as a template parameter when creating a `HashTable`. – R Sahu Jan 02 '16 at 08:46
  • Ah, I see the benefits now. Thanks, great answer. – not_too_shabby Jan 02 '16 at 09:07
  • 1
    *"generic logic that can be used generate a hash value for all types. Treat the bytes that make up k like the characters in a string."* - just have to be a little bit careful about types for which not all bits contribute to the value representation, or for which equivalence is more complicated due to e.g. case insensitive comparison. – Tony Delroy Jan 04 '16 at 02:46
  • 2
    I think that this is only valid for POD types. (The generic `Hash` could `static_assert(std::is_pod::value, "not POD")` this.) And like @TonyD says, even there you could have bad surprises with padding bytes and the like. I think there is a reason the standard library does not provide a generic hash for user-defined types. – 5gon12eder Jan 04 '16 at 03:14
  • Note that if you want to be clever, you can use SFINAE magic to detect if the templated type contains e.g. a hashCode() method, and if so, automagically call that to compute the hash code; or if it doesn't have one, fall back to the default POD logic to compute the hash (be sure to include the static_assert suggested by 5gon12eder so that attempting to use the POD logic on a non-POD type becomes a compile-time error and not a nasty run-time problem). SFINAE magic details here: http://stackoverflow.com/questions/257288/is-it-possible-to-write-a-c-template-to-check-for-a-functions-existence – Jeremy Friesner Jan 04 '16 at 03:41