Как я могу использовать пользовательский тип для ключей в boost::unordered_map?

StackOverflow https://stackoverflow.com/questions/1829639

Вопрос

Прямо сейчас я использую реализацию хэш-карты Boost в проекте и пытаюсь реализовать пользовательский тип для ключей.У меня есть четыре целых числа без знака, которые я хотел бы объединить в один 128-битный тип данных для использования в качестве ключа.

Я создал структуру с 32-разрядным целочисленным массивом из четырех элементов, который служит моим хранилищем.Честно говоря, я не уверен, как работает хэш-карта Boost, поэтому я не уверен, что я здесь делаю, но я следовал документации Boost (http://www.boost.org/doc/libs/1_37_0/doc/html/hash/custom.html) для расширения boost::hash, и я создал хэш-функцию, а также пользовательский оператор сравнения.

У меня есть этот пользовательский тип, определенный в заголовке.Это мой код:

#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

Теперь, когда я на самом деле использую этот тип в неупорядоченной карте Boost, мой код компилируется, но не удается связать.Компоновщик утверждает, что у меня есть символ, определенный несколько раз в нескольких объектных файлах.Мне бы очень хотелось, чтобы мой 128-битный тип работал с этой картой.Есть какие-нибудь советы о том, что я напортачил, или лучший способ сделать это?

Это было полезно?

Решение

Использование неупорядоченной карты почти случайно связано с проблемой, с которой вы столкнулись.Настоящая проблема заключается в том, что вы определяете hash_value и operator== в каждом файле, который содержит приведенный выше заголовок.

Вы можете вылечить это любым из двух способов:

  1. Определение обоих из них как встроенных функций
  2. Просто объявляю их в заголовке

Если вы сделаете последнее (и это то, что вы обычно хотите), вы переместите определения этих функций в .cpp файл (или любое расширение, которое вы используете для исходных файлов C ++).Затем вы скомпилируете этот файл и свяжете результирующий объект с другим вашим кодом, использующим тип int128.

Редактировать:Вы все еще можете сделать свое сравнение более чистым, что-то вроде:

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]);
}

Другие советы

Компоновщик утверждает, что у меня есть символ определенный несколько раз в нескольких объектных файлах.

объявите свои функции как inline

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top