在无序映射中为unique ptr使用std::hash

4

我将尝试在一个映射中保存一个多态类型作为键。

我想出了以下两个结构:

请注意,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作为键?
编辑2:
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;
}

};

他们够用吗?

unique_ptr通过引用传递给operator() - user3072164
@jogojapan,在我看来,标准哈希似乎是通过指针地址进行哈希的,而提问者想要通过指针所指向的对象值进行哈希,可以看一下他们的cmp_games实现。 - user3072164
比较器有什么问题?请解释一下比较器似乎也无法正常工作的具体情况。 - Oswald
似乎无序映射的第三个参数是哈希,而第四个参数是比较器。问题是如何在不传递第三个参数的情况下将比较器作为第四个参数传递?也许可以为哈希设置默认值? - Rouki
@Rouki 如果你按照下面任意一个答案的建议,就不需要显式地提供第三个或第四个模板参数。 - Praetorian
显示剩余6条评论
2个回答

4

标准提供了一种特化,使得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
}

0
game 以 const 引用的方式传递给 std::hash::operator():
template<>
struct std::hash<std::unique_ptr<Game>> {
    size_t operator()(const std::unique_ptr<Game>& game) const;
}

同样适用于cmp_games::operator()


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接