specialise a hash function


I'm attempting to copy the code from wikipedia for applying a hash function on unordered map.
The idea came from the following code:
https://en.wikipedia.org/wiki/Unordered_associative_containers_(C%2B%2B)#Custom_hash_functions


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <unordered_map>

// should take double or long double
template <typename T>
struct custom_struct{T a, b, c;};

// if int, then use explicit structure
template <>
struct custom_struct{int a, b, c;};

// custom hash_function
struct hash_custom {
  size_t operator()(const custom_struct & x) const {
    return std::hash<int>()(x.a) ^ std::hash<int>()(x.b) ^ std::hash<int>()(x.c);
  }
};

// specialise standard std::hash function
template <>
class hash<Y> {
  public :
    size_t operator()(const custom_struct & y ) const {
      return hash<Y>()(y.a) ^ hash<Y>()(y.b) * hash<Y>()(y.c);
    }
};

int main() {
  std::unordered_map<custom_struct, int, hash_custom> int_map; // uses explicit custom struct
  std::unordered_map<custom_struct<double>, hash<double> > double_map; // uses template custom struct

  return 0;
}


I get a compile error though on line 10:
 
error: template specifiers not specified in declaration of ‘template<class T> struct custom_struct’


Any help would be much appreciated.
> template specifiers not specified in declaration of ‘template<class T> struct custom_struct’

1
2
3
template <> 
// struct custom_struct { int a, b, c; };
struct custom_struct<int> { int a, b, c; }; // specialisation for int 


Something like this, perhaps:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <iostream>
#include <unordered_map>

// should take double or long double
template < typename T > struct custom_struct { T a, b, c; /* ... */ };

// if int, then use explicit structure
template <> struct custom_struct<int>{ int a, b, c; /* ... */ };

// custom hash_function
struct hash_custom {

  template < typename T >
  std::size_t operator()( const custom_struct<T>& x ) const {

    static const std::hash<T> hash ;
    return hash(x.a) ^ hash()(x.b) ^ hash(x.c); // *** not a good way to combine hash values
  }
};

// a better custom hash_function ( lifted from boost hash_combine)
struct hash_custom_2 {

    template < typename T >
    static std::size_t combine( std::size_t& seed, const T& v ) {

        return seed ^= std::hash<T>{}(v) + 0x9e3779b9 + ( seed << 6U ) + ( seed >> 2U );
    }

      template < typename T >
      std::size_t operator()( const custom_struct<T>& x ) const {

        std::size_t hash_val = std::hash<T>{}( x.a ) ;
        combine( hash_val, x.b ) ;
        return combine( hash_val, x.c ) ;
      }
};

int main()  {

  std::unordered_map< custom_struct<int>, double, hash_custom > int_map; // uses explicit custom struct
  std::unordered_map< custom_struct<double>, long, hash_custom > double_map; // uses template custom struct

  std::unordered_map< custom_struct<int>, double, hash_custom_2 > int_map2 ; // uses explicit custom struct
  std::unordered_map< custom_struct<double>, long, hash_custom_2 > double_map2 ; // uses template custom struct

}
Last edited on

thank you very much. Much appreciated. Took a while to get my head round this :'‑)

Topic archived. No new replies allowed.