12

I need to insert a 1D array into the hashset.

But I got error while compiling.

#include <stdio.h>
#include <stdlib.h>
#include <hash_set.h>
using namespace std;
int hash_comp(const int* state1,const int* state2) {
    int result = 0;

    for (i = 0; i < 16; i++) 
    {
        if (state1[i] != state2[i]) {
            result = -1;
        }

    }
    return result;
}
struct eqArray
{
    bool operator()(const int* a1,const int* a2) const
  {
    return hash_comp(a1,a2) == 0;
  }
};
hash_set<int*,hash<int*>,eqArray> closelist;
int main(int argc, char** argv)
{
   const int sn[16] = {1,2,3,4,5,6,0,8,9,10,11,12,13,14,7,15};
   closelist.insert(sn);
   return 0;
}
/usr/include/c++/4.2.1/ext/hashtable.h: In member function 'size_t __gnu_cxx::hashtable<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, _Alloc>::_M_bkt_num_key(const _Key&, size_t) const [with _Val = int*, _Key = int*, _HashFcn = __gnu_cxx::hash<int*>, _ExtractKey = std::_Identity<int*>, _EqualKey = std::equal_to<int*>, _Alloc = std::allocator<int*>]':
/usr/include/c++/4.2.1/ext/hashtable.h:599:   instantiated from 'size_t __gnu_cxx::hashtable<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, _Alloc>::_M_bkt_num(const _Val&, size_t) const [with _Val = int*, _Key = int*, _HashFcn = __gnu_cxx::hash<int*>, _ExtractKey = std::_Identity<int*>, _EqualKey = std::equal_to<int*>, _Alloc = std::allocator<int*>]'
/usr/include/c++/4.2.1/ext/hashtable.h:1006:   instantiated from 'void __gnu_cxx::hashtable<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, _Alloc>::resize(size_t) [with _Val = int*, _Key = int*, _HashFcn = __gnu_cxx::hash<int*>, _ExtractKey = std::_Identity<int*>, _EqualKey = std::equal_to<int*>, _Alloc = std::allocator<int*>]'
/usr/include/c++/4.2.1/ext/hashtable.h:437:   instantiated from 'std::pair<__gnu_cxx::_Hashtable_iterator<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, _Alloc>, bool> __gnu_cxx::hashtable<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, _Alloc>::insert_unique(const _Val&) [with _Val = int*, _Key = int*, _HashFcn = __gnu_cxx::hash<int*>, _ExtractKey = std::_Identity<int*>, _EqualKey = std::equal_to<int*>, _Alloc = std::allocator<int*>]'
/usr/include/c++/4.2.1/ext/hash_set:197:   instantiated from 'std::pair<typename __gnu_cxx::hashtable<_Value, _Value, _HashFcn, std::_Identity<_Tp>, _EqualKey, _Alloc>::const_iterator, bool> __gnu_cxx::hash_set<_Value, _HashFcn, _EqualKey, _Alloc>::insert(const typename __gnu_cxx::hashtable<_Value, _Value, _HashFcn, std::_Identity<_Tp>, _EqualKey, _Alloc>::value_type&) [with _Value = int*, _HashFcn = __gnu_cxx::hash<int*>, _EqualKey = std::equal_to<int*>, _Alloc = std::allocator<int*>]'
src/ods2.cpp:677:   instantiated from here
Mat
  • 202,337
  • 40
  • 393
  • 406
weeo
  • 2,619
  • 5
  • 20
  • 29
  • By the way, the `.h` headers and all the pointers and the `return 0;` inside `main` suggest that you are learning C++ from a very poor source. Do yourself a favor and buy [a decent book](http://stackoverflow.com/questions/388242/). – fredoverflow Nov 06 '11 at 12:21

3 Answers3

14

If you use a std::array<int, 16> instead of int*, all your problems will go away. If you have no C++11 compiler, you can use boost::array instead. Also, replace hash_set with unordered_set.

It appears there is no specialization of std::hash for std::arrays, so I wrote my own:

#include <unordered_set>
#include <array>

namespace std
{
    template<typename T, size_t N>
    struct hash<array<T, N> >
    {
        typedef array<T, N> argument_type;
        typedef size_t result_type;

        result_type operator()(const argument_type& a) const
        {
            hash<T> hasher;
            result_type h = 0;
            for (result_type i = 0; i < N; ++i)
            {
                h = h * 31 + hasher(a[i]);
            }
            return h;
        }
    };
}

std::unordered_set<std::array<int, 16> > closelist;

int main()
{
    std::array<int, 16> sn = {1,2,3,4,5,6,0,8,9,10,11,12,13,14,7,15};
    closelist.insert(sn);
}
fredoverflow
  • 256,549
  • 94
  • 388
  • 662
  • thank you, so what library should I include instead of hash_set.h? and how can I declare these? like {unordered_set,hash>,??which function?> closelist;} – weeo Nov 06 '11 at 12:39
  • You could use `#include `, `#include `, and `std::tr1::unordered_set >`. – Kerrek SB Nov 06 '11 at 12:43
  • I still got error: ` /usr/include/c++/4.2.1/tr1/hashtable_policy.h:784: error: using invalid field 'std::tr1::__detail::_Hash_code_base<_Key, _Value, _ExtractKey, _Equal, _H1, _H2, std::tr1::__detail::_Default_ranged_hash, false>::_M_h1' make[2]: *** [build/Debug/GNU-MacOSX/src/ods2.o] Error 1` – weeo Nov 06 '11 at 13:02
  • `src/ods2.cpp:69: error: specialization of 'template struct std::tr1::hash' in different namespace /usr/include/c++/4.2.1/tr1/functional_hash.h:48: error: from definition of 'template struct std::tr1::hash'` src/ods2.cpp:69: error: specialization of 'template struct std::tr1::hash' in different namespace /usr/include/c++/4.2.1/tr1/functional_hash.h:48: error: from definition of 'template struct std::tr1::hash' make[2]: *** [build/Debug/GNU-MacOSX/src/ods2.o] Error 1 – weeo Nov 06 '11 at 13:48
  • Wow, your compiler must be quite old :) Either update, or nest the specialization of `hash` inside the `tr1` namespace, that is: `namespace std { namespace tr1 { template ... } }`. – fredoverflow Nov 06 '11 at 13:54
  • I'm using the newest MPIC++ for compiling. So I need to do in the second way? – weeo Nov 06 '11 at 20:23
  • Wow!..Thank you very much! it is working now. So I need to put std::array instead of int[16]? I wonder what is the difference? – weeo Nov 06 '11 at 20:30
  • `std::array` is a zero-overhead wrapper around a `T[N]` that gets rid of all the ridiculous special rules and limitations of C arrays. – fredoverflow Nov 06 '11 at 20:54
  • Thank you again! I'm coding this in C, but I didn't find any hashset library in C, so I changed my code into c++. I wonder do you know any hashset in C? and...Can you explain the hash<>function a little bit? so next time when I need a hash<> for 2D array I know how to write it? – weeo Nov 06 '11 at 21:43
  • The hash function for arrays simply calls the hash functions for its elements and multiplies them by a prime factor before adding them to an accumulator. This is basically `java.lang.String.hashCode()` if you will ;) You don't need to write a different function for 2D arrays. The code is generic enough for arrays of *any* element type that supports hashing, so it automatically works for multidimensional arrays such as `std::array, 20>` without any additional effort. – fredoverflow Nov 06 '11 at 22:42
  • Where does the magic `31` in your hash calculation come from? – Baum mit Augen Feb 01 '15 at 17:09
  • 1
    @BaummitAugen I stole it from `java.lang.String.hashCode`. It seems to be a popular number, because it is prime, and `31 * x` can be implemented quite efficiently as `(x << 5) - x`. – fredoverflow Feb 01 '15 at 17:19
0

You didn’t post the actual error message, only the trace. That said, it’s probably because your set uses non-const int* while your data is const.

That said, I’d suggest using unordered_set instead of hash_set(either from std::tr1 if your compiler supports that, or from std if your compiler supports C++11 or from Boost), and heed Fred’s advice of using an {std,boost}::array instead of a raw pointer.

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • I got this error message: /usr/include/c++/4.2.1/tr1/hashtable_policy.h:784: error: using invalid field 'std::tr1::__detail::_Hash_code_base<_Key, _Value, _ExtractKey, _Equal, _H1, _H2, std::tr1::__detail::_Default_ranged_hash, false>::_M_h1' make[2]: *** [build/Debug/GNU-MacOSX/src/ods2.o] Error 1 – weeo Nov 06 '11 at 13:04
0

I don't think that there exists a specialized hash<int*>. I added this:

namespace __gnu_cxx{ //I'm not sure what compiler version you used,
                     //mine wanted this
    template<>
    struct hash<const int*>{
        size_t operator()(const int*a) const{
            size_t r = 0;
            for (int i=0;i<16;i++)
                r = (r<<1) ^ a[i]; //not sure if it makes sense as a hash.
            return r;
        }
    };
}

I also put in some consts and it compiles.

Vlad
  • 18,195
  • 4
  • 41
  • 71