std :: hash для уникального ptr в неупорядоченной карте

Я пытаюсь держать полиморфный тип в качестве ключа на карте.

Я придумал следующие две структуры:

Обратите внимание, что Game абстрактный класс и структура данных, которую я использую:

std::unordered_map<gamePtr,int> _allGames;

в то время как gamePtr это typedef за:

unique_ptr<Game>

template<>
struct std::hash<std::unique_ptr<Game>> {
size_t operator()(std::unique_ptr<Game> game) const {
return (std::hash<string>()(std::to_string(game->firstTeamFinalScore()) + game->firstTeam() + game->secondTeam()));
}

};

struct cmp_games {
bool operator() (std::unique_ptr<Game> game1, std::unique_ptr<Game> game2) const {
return *game1 == *game2;
}
};

cmp_games компаратор, кажется, работает нормально, но std::hash не потому, что пытается скопировать unique_ptr (Что, разумеется, невозможно), и я не знаю, как с этим справиться.
Хотелось бы услышать некоторые предложения (если это даже возможно).

РЕДАКТИРОВАТЬ: Компаратор также, кажется, не работает должным образом. как мне заставить эту карту работать правильно с unique_ptr как ключ?

EDIT2:

Придумали:

template<>
struct std::hash<std::unique_ptr<Game>> {
size_t operator()(const std::unique_ptr<Game>& game) const {
return (std::hash<string>()(std::to_string(game->firstTeamFinalScore()) + game->firstTeam() + game->secondTeam()));
}
};

template<>
struct std::equal_to<std::unique_ptr<Game>> {
bool operator() (const std::unique_ptr<Game>& game1,const std::unique_ptr<Game>& game2) const {

return *game1 == *game2;
}

};

Должны ли они быть достаточно?

3

Решение

Стандарт обеспечивает специализацию чтобы std::hash<unique_ptr<T>> такой же как std::hash<T*>, Так что предоставьте специализацию для std::hash<Game *>, Например:

#include <iostream>
#include <memory>
#include <unordered_map>
#include <cstdlib>

struct foo
{
foo(unsigned i) : i(i) {}
unsigned i;
};

namespace std {

template<>
struct hash<foo *>
{
size_t operator()(foo const *f) const
{
std::cout << "Hashing foo: " << f->i << '\n';
return f->i;;
}
};

}

int main()
{
std::unordered_map<std::unique_ptr<foo>, int> m;
m.insert(std::make_pair(std::unique_ptr<foo>(new foo(10)), 100));
m.insert(std::make_pair(std::unique_ptr<foo>(new foo(20)), 200));
}

Живая демо


Другой вариант — изменить существующий std::hash специализация, так что он принимает unique_ptr по ссылке.

size_t operator()(std::unique_ptr<Game> const& game) const
//                                      ^^^^^^ no more copying

РЕДАКТИРОВАТЬ: std::unique_ptr обеспечивает операторы сравнения которые сравнивают управляемые указатели. Если вы хотите unordered_map чтобы проверить Game сами объекты для равенства, обеспечивают operator== перегрузка вместо специализации std::equal_to

inline bool operator==(const std::unique_ptr<Game>& game1,
const std::unique_ptr<Game>& game2)
{
return *game1 == *game2;
}

Это, в свою очередь, требует, чтобы вы предоставили оператор равенства для Game (или вы можете просто добавить логику к функции выше).

inline bool operator==(Game const& game1, Game const& game2)
{
return // however you want to compare these
}
4

Другие решения

Пройти game по ссылке в std::hash::operator():

template<>
struct std::hash<std::unique_ptr<Game>> {
size_t operator()(const std::unique_ptr<Game>& game) const;
}

То же самое относится и к cmp_games::operator(),

0

По вопросам рекламы [email protected]