Введение
Привет всем, я пытаюсь использовать boost::unordered_set
для пользовательского типа класса.Класс хранит информацию о координатах и некоторых других значениях, но только координаты используются для создания значения хеш-функции.Теперь, если я хочу вставить точку, и уже есть точка с равными координатами (отсюда набор), мне нужно изменить третье значение от исходного объекта (например, object.isDuplicate = true
, очень упрощенный ).Пожалуйста, не слишком привязывайтесь к значению bool и обнаружению дубликатов, потому что в исходном коде это немного сложнее, но это должно только показать, что мне нужен неконстантный доступ к хранимому классу.Я могу использовать только boost 1.53 и C ++ 03 и GCC 4.4.3
Проблема
Проблема сейчас, когда я пытаюсь вставить точку с boost::unordered_set::insert
, я получаю pair<iterator, bool>
из которых первый член является неизменяемым итератором для вставленной или исходной записи, а второй - bool
, указывающим, было ли введено значение или нет.Я не могу изменить значение с помощью неизменяемого итератора, к сожалению, поэтому мне пришлось думать о чем-то другом.Поэтому теперь я пытаюсь сохранить указатель на мой объект в наборе, а затем получить к нему доступ через этот указатель, чтобы изменить значение (что должно быть в порядке, поскольку значение не имеет ничего общего со значением хеш-функции и, следовательно, не изменяет ключ).Поэтому я попытался перегрузить функцию boost::hash_value
, чтобы принять указатель на мой класс следующим образом:
size_t hash_value(const A * a) {
size_t seed = 0;
boost::hash_combine(seed, a->a);
boost::hash_combine(seed, a->b);
return seed;
}
Но, похоже, unordered_set
не использует мою перегруженную функцию (я пытался напечатать семя вконец, но он не отображается, поэтому я предполагаю, что он использует другую перегрузку), даже если я инициализирую свой набор с unordered_set< A *, boost::hash<A *> >
.Что касается хэширования: когда я пытаюсь использовать набор без указателя, он работает нормально, но я не могу изменить значение.
Возможная проблема
Я немного искал в Boost :: ссылка хеша и обнаружил эту перегрузку template<typename T> std::size_t hash_value(T* const&);
, которая, я думаю, используется вместо моей собственной (и просто хэши с адресом объектов), но затем я удивляюсь, почему мой компилятор не запрашивает переопределение этой функции (я компилирую с включенными -Wall -Wextra -pedantic
флажками.
Вопрос
Так это реальная проблема? И если это так, как я могу сказать моему компилятору явно использовать мою пользовательскую хеш-функцию?
Код
Наконец, небольшой пример, который я написал, чтобы проверить все
#include <iostream>
#include <string>
#include <boost/functional/hash.hpp>
#include <boost/unordered_set.hpp>
using boost::unordered_set;
struct A {
double a;
double b;
bool isDup;
A(const double a, const double b): a(a), b(b), isDup(false) {}
A(const A & a): a(a.a), b(a.b), isDup(a.isDup) {}
/* Two equal As ought to have a bitwise equal floating point value so this is okay */
bool operator==(const A & a) const {
if (a.a != this->a) return false;
if (a.b != this->b) return false;
return true;
}
};
size_t hash_value(const A * a) {
size_t seed = 0;
boost::hash_combine(seed, a->a);
boost::hash_combine(seed, a->b);
std::cout << "Seed: " << seed << std::endl; /* This is not printed so i assume the function is not called */
return seed;
}
int main() {
A a1(1.2, 2.3);
A a2(2.3, 3.4);
A a3(3.4, 4.5);
A a4(a1);
unordered_set< A *, boost::hash<A *> > usa; /* This was unintended lol */
if ( ! usa.insert(&a1).second ) std::cout << "Error " << a1.a << ", " << a1.b << " is already in set" << std::endl;
if ( ! usa.insert(&a2).second ) std::cout << "Error " << a2.a << ", " << a2.b << " is already in set" << std::endl;
if ( ! usa.insert(&a3).second ) std::cout << "Error " << a3.a << ", " << a3.b << " is already in set" << std::endl;
if ( ! usa.insert(&a4).second ) {
/* This is not called */
std::cout << "Error " << a4.a << ", " << a4.b << " is already in set" << std::endl;
(*(usa.insert(&a4).first))->isDup = true;
}
}