std::hash 特化仍未被 std::unordered_map 使用

Posted

技术标签:

【中文标题】std::hash 特化仍未被 std::unordered_map 使用【英文标题】:std::hash specialization remains unused by std::unordered_map 【发布时间】:2015-05-07 12:46:31 【问题描述】:

我正在尝试通过为const char 提供特化来扩展std::hash<T>,以便我可以使用const char* 作为std::unordered_map 中的键类型。

这是我尝试过的:

#include <unordered_map>
#include <functional>
#include <stdio.h>
#include <string.h>
#include <ctype.h>

namespace std

    template<>
    struct hash<const char*>
    
        size_t operator()(const char* const& s) const
        
           size_t h = 0;
           const char* tmp = s;

           while (*tmp)
              h = (h << 5) + h + (unsigned char)toupper(*tmp++);

           printf("hash of '%s' is (%ld)\n", s, h);
           return h;
        
    ;


int main(int argc, char* argv[])

   const char* name1= "Mark Nelson";
   const char* name2= strdup(name1);

   std::unordered_map<const char*, int> map;

   printf("Insert (%s)\n", name1);
   map[name1]= 100;

   printf("Lookup (%s)\n", name1);
   printf("map[%s](name1) = %d\n", name1, map.find(name1) != map.end() ? map.find(name1)->second : -1);
   printf("Lookup (%s)\n", name2);
   printf("map[%s](name2) = %d\n", name2, map.find(name2) != map.end() ? map.find(name2)->second : -1);

   return 0;

输出是什么:

Insert (Mark Nelson)
hash of 'Mark Nelson' is (121066894705597050)
Lookup (Mark Nelson)
hash of 'Mark Nelson' is (121066894705597050)
hash of 'Mark Nelson' is (121066894705597050)
map[Mark Nelson](name1) = 100
Lookup (Mark Nelson)
hash of 'Mark Nelson' is (121066894705597050)
map[Mark Nelson](name2) = -1

所以在我看来,std::unordered_map 正在使用我提供的哈希实现来进行插入和查找。但是由于某种原因,它没有通过name2找到值,这似乎是仍然使用指针比较。

这里有什么问题?我用的是GCC 4.8.2,文件是用g++ -std=c++11 main.cc编译的

【问题讨论】:

std中定义东西通常不是一个好主意。 @Lingxi 我在一定程度上同意,但您需要在其特定命名空间中重载模板。 【参考方案1】:

对于无序地图,您需要两件事 (ref):

    哈希函数 相等的比较函数

因此,您有 (1) 似乎可以工作,但是地图必须检查 const char * 是否相等,这会演变为指针比较。为此,您可以指定一个自定义比较器 (ref):

struct cmp_str

   bool operator()(char const *a, char const *b)
   
      return std::strcmp(a, b) == 0;
   
;

std::unordered_map<const char*, int, std::hash<const char *>, cmp_str> BlahBlah;

【讨论】:

谢谢。我已经实现了std::equal_to&lt;const char*&gt;,现在它可以按预期工作了。 @user826955 如果它依赖于用户定义的类型,您只能向std 添加特化,因为未定义行为的痛苦;你的hash&lt;const char *&gt;equal_to&lt;const char *&gt; 都不依赖于一个。编写您自己的哈希器和比较器类型,而不是劫持标准的。 问题确实是,当我定义我的 hasher 和 compare 函数时,我同意实现了同样的事情,但是如果你打算使用 STL 周围的包装器,使用会变得更加不舒服。例如template &lt;typename KEY, typename VALUE&gt; class FoobarMar 作为专有实现,使用 std::map&lt;KEY, VALUE&gt;。扩展 std 命名空间只会让它工作,而提供函数会使 API 复杂化(尤其是在使用继承时)。注意我们一般不使用std命名空间。

以上是关于std::hash 特化仍未被 std::unordered_map 使用的主要内容,如果未能解决你的问题,请参考以下文章

对纯整数数组使用 C++ std::hash 内置特化

如何为用户定义的类型专门化 std::hash<T>?

Ubuntu中使用dpkg安装deb文件提示依赖关系问题,仍未被配置

(转)Ubuntu中使用dpkg安装deb文件提示依赖关系问题,仍未被配置

std::unordered_map::find 使用不同于 Key 类型的类型?

在 C++ std::unordered_map 中预分配桶