не может содержать пользовательский класс в hash_set

Я реализую шестиуровневую задачу Кевина Бэкона и пишу класс для узла актора. Я могу использовать набор, но не контейнер hash_set для хранения пользовательского класса. Зачем? сообщение об ошибке показывает: error C2440: 'type cast': невозможно преобразовать из 'const ActorGraphNode' в 'size_t' 1> Нет доступного пользовательского оператора преобразования, который может выполнить это преобразование, или оператор не может быть вызван....

#include <hash_set>
#include <set>
class ActorGraphNode{
    public: 
    string ActorName;
    //hash_set<ActorGraphNode> linkedActors;
    set<ActorGraphNode> linkedActors;
    ActorGraphNode(string name):ActorName(name){}
    void linkCostar(ActorGraphNode actor){
       linkedActors.insert(actor);
       actor.linkedActors.insert(*this);
    }
    bool operator<( const ActorGraphNode& a ) const
    { return ActorName < a.ActorName ? true : false;}
};

person user389955    schedule 29.05.2013    source источник


Ответы (2)


Неудивительно, что hash_set требует от вас реализации хеш-функции для вашего типа.

class ActorGraphNode{
    public: 
    string ActorName;
    hash_set<ActorGraphNode> linkedActors;
    //set<ActorGraphNode> linkedActors;
    ActorGraphNode(string name):ActorName(name){}
    void linkCostar(ActorGraphNode actor){
       linkedActors.insert(actor);
       actor.linkedActors.insert(*this);
    }
    bool operator<( const ActorGraphNode& a ) const
    { return ActorName < a.ActorName;}
    bool operator ==( const ActorGraphNode& a ) const
    { return ActorName == a.ActorName;}
    operator size_t() const
    {
      return hash<string>()(ActorName);
    }
};
person riv    schedule 29.05.2013
comment
Вам также необходимо равенство, а operator< не требуется для неупорядоченных/хэш-контейнеров. - person Nathan Ernst; 30.05.2013
comment
Равенство может быть сгенерировано компилятором, но, конечно, вы можете написать свое собственное, если, скажем, вы не хотите иметь накладные расходы на сравнение всего набора linkedActors. - person riv; 30.05.2013
comment
Я думаю, что лучше сделать свою собственную специализацию для std::hash‹ActorGraphNode› вместо создания оператора size_t - person Evgeny Eltishev; 30.05.2013
comment
Евгений, не могли бы вы привести пример того, как написать хэш‹ActorGraphNode›? мой исходный код не может быть скомпилирован, потому что пропущен оператор size_t, поэтому я добавил его. - person user389955; 30.05.2013
comment
@riv, operator== не создается компилятором. См. §12, параграф 1: Конструктор по умолчанию (12.1), конструктор копирования и оператор присваивания копирования (12.8), конструктор перемещения и оператор присваивания перемещения (12.8) и деструктор (12.4) являются специальными функциями-членами. [Примечание: реализация будет неявно объявлять эти функции-члены для некоторых типов классов, если программа не объявляет их явно. Реализация будет неявно определять их, если они используются odr (3.2). См. 12.1, 12.4 и 12.8. —конец примечания] Программы не должны определять неявно объявленные специальные функции-члены. - person Nathan Ernst; 30.05.2013
comment
@riv, не хватило места, это единственные разрешенные методы, сгенерированные компилятором. Если ваш компилятор генерирует operator==, это расширение, а не стандарт. - person Nathan Ernst; 30.05.2013
comment
@Nathan: ой, ты прав, я думал, что это потому, что ошибки не было, но, видимо, это заканчивается проверкой равенства путем приведения объекта к size_t. - person riv; 30.05.2013
comment
@Евгений Елтишев: std::hash используется unordered_set; hash_set, похоже, использует stdext::hash_value, по крайней мере, в VC10. Переход на unordered_set действительно облегчит задачу, так как вы также сможете отказаться от оператора сравнения. - person riv; 30.05.2013

спасибо всем за ваши ответы и комментарии. Вот мой обновленный код с вашей помощью. плюс для функции linkCostar() я сейчас использую передачу по ссылке:

class ActorGraphNode{
public: 
    string ActorName;
    hash_set<ActorGraphNode> linkedActors;
    ActorGraphNode(string name):ActorName(name){}
    void linkCostar(ActorGraphNode& actor){
        linkedActors.insert(actor);
        actor.linkedActors.insert(*this);
    }
    bool operator==( const ActorGraphNode& a ) const
    { return ActorName == a.ActorName ? true : false;}
    operator size_t() const
    {
        const int HASHSIZE = 501;
        int seed = 131;
        size_t sum = 0;
        for(size_t i = 0; i < ActorName.length(); ++i) 
            sum = (sum * seed) + ActorName[i];      
        return sum % HASHSIZE;
    }
};
person user389955    schedule 29.05.2013
comment
STL имеет хеш-функцию для строк, поэтому вам не нужно писать свою собственную; если вы это сделаете, не возвращайте результат по модулю HASHSIZE, вы в основном увеличиваете количество столкновений, заставляя свои значения в диапазоне 0..500. - person riv; 30.05.2013
comment
Спасибо, вот мое обновление для оператора size_t: operator size_t() const {hash‹string› H; вернуть H (Имя Актера); } - person user389955; 30.05.2013