STL unordered_map中自定义key的约束

开始之前,先上unordered_map的定义:

template<class Key,
    class Ty,
    class Hash = std::hash<Key>,
    class Pred = std::equal_to<Key>,
    class Alloc = std::allocator<std::pair<const Key, Ty> > >
    class unordered_map;
    > class unordered_map

当我们在使用自定义类型作为unordered_map的key的时候,要求我们的自定义类型满足一下两点:

1. 提供hash函数

这是由于unordered_map的底层数据结构是hash table,所以需要一个hash函数来将key序列化然后返回哈希值

class Dylan
{
public:
    Dylan() { name = ""; addr = ""; }
    Dylan(std::string na, std::string ad) : name(na), addr(ad) {};
    const string getName() const { return name; }
    const string getAddr() const { return addr; }
    
private:
    std::string name;
    std::string addr;
    int age = 0;
};
namespace std //用自定义类型特例化一个hash模板,间接调用原生hash
{
    template<>
    struct hash<Dylan>
    {
        size_t operator() (const Dylan& s) const noexcept
        {
            string hasStr = s.getName() + "+" + s.getAddr();
            return std::hash<std::string>(hasStr);  // 调用原生hash.
        }
    };
}
 
int main()
{
    unordered_map<Dylan, int> map;
    Dylan dy1("111","222");
    Dylan dy2("222","333");
    map.insert({ dy1,1 });
    map.insert({ dy2,2 });
    cout << map[dy1] << " " << map[dy2] << endl;
 
	system("pause");
	return 0;
}

unordered_map 的默认hash函数是一个名为hash的模板,template<> hash{},当然我们也可以自定义一个hash函数,然后在声明map的时候把这个自定义函数的名字传进来,就像下面这样:

class Dylan{...}
struct myOwnHash
{
    size_t operator() (const Dylan& s) const noexcept
    {
         string hasStr = s.getName() + "+" + s.getAddr();
         return std::hash<std::string>(hasStr);
    }
}; 
int main()
{
    unordered_map<Dylan, int, myOwnHash> map;
    ....
}

2. 提供eqaul_to函数

当我们编译时,发现还会遇到如下error:


error C2676: binary '==': 'const _Ty' does not define this operator 
or a conversion to a type acceptable to the predefined operator
 message : see reference to function template instantiation 'bool std::equal_to<_Kty>::operator ()(const _Ty &,const _Ty &) const' being compiled

这是因为,unordered_map 还需要一个可以比较两个key是否相等的函数,实际上unordered_map会提供一个缺省的equal_To函数,这是个模板函数,他会以我们自定义的类型来实例化,然后调用自定义类型(即Dylan)的==运算符,那么消除上面这个error的办法也就显而易见了,依然有两种方法。方法一是在类定义中,重载==运算符

class Dylan
{
public:
    Dylan() { name = ""; addr = ""; }
    Dylan(std::string na, std::string ad) : name(na), addr(ad) {};
    const string getName() const { return name; }
    const string getAddr() const { return addr; }
    
    
   bool operator==(const Dylan& dy1) const { return this->getName() == dy1.getName(); }
   //切记,将这个函数声明为const类型,否则会遇到编译错误
private:
    std::string name;
    std::string addr;
    int age = 0;
};
int main()
{
    unordered_map<Dylan, int> map; //这样就可以像往常一样使用unordered_map了
    Dylan dy1("111","222");
    Dylan dy2("222","333");
    map.insert({ dy1,1 });
    map.insert({ dy2,2 });
    cout << map[dy1] << " " << map[dy2] << endl;
 
	system("pause");
	return 0;
}

方法二是自定义自己的equalto函数,让后将该函数名字放入声明的第四个参数中

class Dylan{...}
struct myOwnHash
{
    size_t operator() (const Dylan& s) const noexcept
    {
         std::hash<string> myhash;
         string hasStr = s.getName() + "+" + s.getAddr();
         return myhash(hasStr);
    }
}; 
struct myOwnEqualTo
{
    size_t operator() (const Dylan& s, const Dylan& s1) const noexcept
    {
        return (s.getName() == s1.getName());
    }
}; 
int main()
{
    unordered_map<Dylan,int, myOwnHash,myOwnEqualTo> map;
    ....
}

  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

u010787096

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值