Search code examples
c++arraysc++11hashunordered-set

Using array as key in unordered_set


I want to use an unordered_set having as key an unsigned long long*, but I want to implement the hash and the equal_to using the values stored. For instance:

int size = 4;
typedef unsigned long long verylong;
verylong* x = new verylong[size];
// calc hash and equal using x[0]..x[3]

The easy method is to use a wrapper.

class VeryLong {
verylong* array;
int arraySize;
...
bool operator==(const VeryLong& x) { // use the array and arraySize }
...
};
namespace std {

template <>
class hash<VeryLong>
{
    std::size_t operator()(const VeryLong& v) const
    {

     // Compute hash values for array (using murmur, maybe)
     //...
    }
};

But I don't want to use a wrapper due to memory consumption. I want something like:

std::unordered_set<verylong*,MyHash,MyEqual> set;

The problem is to implement MyHash and MyEqual, because the arraySize is not constant (I only know arraySize in execution time).

I tried this:

typedef struct MyHash
{
    int arraySize;
    MyHash(int size) : arraySize(arraySize) {}
    long operator() (const verylong* const k) const { return hash(k,size); }
} MyHash;

But I cannot use this, because MyHash is not constexpr.

Is what I want possible to do?

EDIT: If I try using the MyHash implemented above:

int size;
// someone sets size a positive value 
std::unordered_set<verylong*,MyHash(size),MyEqual> set;

The following error occurs:

error: temporary of non-literal type 'MyHash' in a constant expression std::unordered_set< verylong*, MyHash(size), MyEquals> set;


Solution

  • The second template argument to std::unordered_set<> should be MyHash rather than MyHash(size), as a type is expected here rather than an object. Change your set declaration to:

    std::unordered_set<verylong*, MyHash, MyEqual> set(bucket_count, MyHash(size));
    

    Presumably MyEqual will need a similar argument for size, in which case do:

    std::unordered_set<verylong*, MyHash, MyEqual> set(bucket_count, MyHash(size), MyEqual(size));
    

    For bucket_count, use a guesstimate of how many elements will be in your set.

    As a side note, don't typedef your structs that way – that's a hideous C-ism that serves no purpose in C++.