How can I use a custom type for keys in a boost::unordered_map?

荒凉一梦 提交于 2019-12-10 11:17:16

问题


I'm using Boost's implementation of a hash map in a project right now, and I'm trying to implement a custom type for keys. I have four unsigned integers which I'd like to combine into a single 128-bit datatype to use as a key.

I've created a struct with a 32-bit integer array of four elements, which serves as my storage. To be honest, I'm not sure how Boost's hash map works, so I'm not sure what I'm doing here, but I followed the Boost documentation (http://www.boost.org/doc/libs/1_37_0/doc/html/hash/custom.html) for extending boost::hash, and I created a hash function, as well as a custom comparison operator.

I have this custom type defined in a header. This is my code:

#ifndef INT128_H_
#define INT128_H_

// Custom 128-bit datatype used to store and compare the results of a weakened hash operation.
struct int128
{
    unsigned int storage[4];

    /* Assignment operation that takes a 32-bit integer array of four elements.
    This makes assignment of values a shorter and less painful operation. */
    void operator=(const unsigned int input[4])
    {
        for(int i = 0; i < 4; i++)
            storage[i] = input[i];
    }
};

bool operator==(int128 const &o1, int128 const &o2)
{
    if(o1.storage[0] == o2.storage[0] && o1.storage[1] == o2.storage[1] && 
       o1.storage[2] == o2.storage[2] && o1.storage[3] == o2.storage[3])
        return true;

    return false;
}

// Hash function to make int128 work with boost::hash.
std::size_t hash_value(int128 const &input)
{
    boost::hash<unsigned long long> hasher;
    unsigned long long hashVal = input.storage[0];

    for(int i = 1; i < 3; i++)
    {
        hashVal *= 37;
        hashVal += input.storage[1];
    }

    return hasher(hashVal);
}

#endif

Now when I actually use this type in Boost's unordered map, my code compiles, but fails to link. The linker claims that I have a symbol defined multiple times in several object files. I'd really like to get my 128-bit type working with this map. Any tips on what I'm screwing up, or a better way to do this?


回答1:


The involvement of unordered-map is almost incidental to the problem you're encountering. The real problem is that you're defining hash_value and operator== in every file that includes the header above.

You can cure this by either:

  1. Defining both those as inline functions
  2. Just declaring them in the header

If you do the latter (and it's what you'll usually want) you'll move the definitions of those functions into a .cpp file (or whatever extension you use for C++ source files). You'll then compile that file, and link the resulting object with your other code that uses the int128 type.

Edit: You can still make your comparison cleaner, something like:

bool operator==(int128 const &o1, int128 const &o2)
{
    return o1.storage[0] == o2.storage[0] && o1.storage[1] == o2.storage[1] && 
           o1.storage[2] == o2.storage[2] && o1.storage[3] == o2.storage[3]);
}



回答2:


The linker claims that I have a symbol defined multiple times in several object files.

declare your functions as inline



来源:https://stackoverflow.com/questions/1829639/how-can-i-use-a-custom-type-for-keys-in-a-boostunordered-map

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!