hash_map中string为key的解决方法

当hash_map中使用string为key时,需用户扩展命名空间,否则报错如下:

/usr/lib/gcc/x86_64-redhat-linux/3.4.5/../../../../include/c++/3.4.5/ext/hashtable.h:518: error: no match for call to `(const __gnu_cxx::hash<std::string>) (const std::basic_string<char, std::char_traits<char>, std::allocator<char> >&)'
表明编译器错误,修改方法有如下几个方案:

方案一:

自己写一个头文件,当使用string为key时,加入该头文件即可。指明了不同编译器下扩展形式。(必杀技)。文件如下:

#ifndef HASH_MAP_HPP
#define HASH_MAP_HPP


#ifdef HAVE_CONFIG_H
#include <config.h>
#endif


#include <string>


#if defined(_STLPORT_VERSION)
    #include <hash_map>
    #include <hash_set>
    using std::hash;
    using std::hash_map;
    using std::hash_set;
#else // not using STLPORT


    #ifdef __GNUC__
        #if __GNUC__ >= 3
            #include <ext/hash_map>
            #include <ext/hash_set>
            namespace __gnu_cxx {
                template <>
                struct hash<std::string> {
                    size_t operator()(const std::string& s) const {
                        unsigned long __h = 0;
                        for (unsigned i = 0;i < s.size();++i)
                            __h ^= (( __h << 5) + (__h >> 2) + s[i]);
                        return size_t(__h);
             
                    }
                   
                };
            }
            using __gnu_cxx::hash_map;
            using __gnu_cxx::hash;
        #else // GCC 2.x
            #include <hash_map>
            #include <hash_set>
            namespace std {
                struct hash<std::string> {
                    size_t operator()(const std::string& s) const {
                        unsigned long __h = 0;
                        for (unsigned i = 0;i < s.size();++i)
                            __h ^= (( __h << 5) + (__h >> 2) + s[i]);
                        return size_t(__h);
                    }
                };
            };
            using std::hash_map;
            using std::hash_set;
            using std::hash;
        #endif // end GCC >= 3
    #elif defined(_MSC_VER) && ((_MSC_VER >= 1300) || defined(__INTEL_COMPILER))
        // we only support MSVC7+ and Intel C++ 8.0
        #include <hash_map>
        #include <hash_set>
        namespace stdext {
            inline size_t hash_value(const std::string& s) {
                unsigned long __h = 0;
                for (unsigned i = 0;i < s.size();++i)
                    __h ^= (( __h << 5) + (__h >> 2) + s[i]);
                return size_t(__h);
            }
        }
        using std::hash_map; // _MSC_EXTENSIONS, though DEPRECATED
        using std::hash_set;
    #else
        #error unknown compiler
    #endif //GCC or MSVC7+
#endif // end STLPORT
#endif /* ifndef HASH_MAP_HPP */

方案二:

想简单一些,快速使用,可遵照如下写法:

#include <iostream>
#include <string>
#include <ext/hash_map>
using namespace std;
using namespace __gnu_cxx;

namespace __gnu_cxx
{
    template<> struct hash<const string>
    {
        size_t operator()(const string& s) const
        { return hash<const char*>()( s.c_str() ); } //
__stl_hash_string
    };
    template<> struct hash<string>
    {
        size_t operator()(const string& s) const
        { return hash<const char*>()( s.c_str() ); }
    };
}

int main( void )
{
    hash_map<string,int> test;
    test["abc"] = 1;
    cout << test["abc"] << endl;
    system( "pause" );
}

方案三:
再扩展一些,当使用long做key时,同样扩展:

#ifndef EXT_HASH_FUNCTION_HPP_INCLUDED
#define EXT_HASH_FUNCTION_HPP_INCLUDED

#ifdef __GNUC__
namespace __gnu_cxx
{
        template<>
        struct hash<long long>
        {
                size_t operator()(long long __x) const
                {
                        if (sizeof(__x) == sizeof(size_t))
                                return __x;
                        else
                                return (__x >> 32) ^ (__x & 0xFFFFFFFF);
                }
        };

        template<>
        struct hash<unsigned long long>
        {
                size_t operator()(unsigned long long __x) const
                {
                        if (sizeof(__x) == sizeof(size_t))
                                return __x;
                        else
                                return (__x >> 32) ^ (__x & 0xFFFFFFFF);
                }
        };

        template<typename Traits, typename Allocator>
        struct hash<std::basic_string<char, Traits, Allocator> >
        {
                size_t operator()(const std::basic_string<char, Traits, Allocator>& __s) const
                {
                        return __stl_hash_string(__s.c_str());
                }
        };

}
#endif

#endif//EXT_HASH_FUNCTION_HPP_INCLUDED

<think>好的,用户之前遇到了一个C++编译错误C2664,具体是关于std::hash<std::string>的类型转换问题,在使用libcuckoo的cuckoohash_map时出现的。现在他想确认是否存在类型转换错误,并了解如何正确使用该容器。我需要仔细分析可能的原因,并给出解决方案。首先,用户的问题可能出在键类型与哈希函数的匹配上。错误提示说无法将参数从“constK”转换为“const std::string”,说明哈希函数期望的是std::string类型,但实际传入的是另一个类型K。这可能是因为用户在声明cuckoohash_map时使用了不同的键类型,比如自定义类型或者没有正确包含头文件。接下来,我需要回忆libcuckoo库的使用方法。cuckoohash_map需要指定键类型、值类型,以及可选的哈希函数和相等比较器。默认情况下,哈希函数是std::hash<Key>,所以如果键类型不是std::string,而用户没有提供自定义哈希,就会导致类型不匹配。用户之前的问题中已经提到过自定义哈希函数的方法,比如特化std::hash或者显式指定哈希模板参数。现在需要确认这些步骤是否正确应用。例如,用户可能在使用自定义类型作为键,但没有为其定义哈希函数,或者头文件没有正确包含。 另外,用户可能误用了类似std::string_view这样的类型作为键,而std::hash对它的支持可能不完整,导致转换错误。需要检查键类型是否为标准库已支持的类型,或者是否正确定义了对应的哈希。可能的解决方案包括:验证键类型是否正确,检查头文件是否包含,特化std::hash,或者显式指定哈希函数类型。此外,还要确保自定义类型的相等运算符已定义,因为哈希和相等比较需要一致。还需要考虑用户是否在项目中正确配置了libcuckoo库,是否存在版本兼容性问题,或者是否有其他模板参数被错误设置。例如,如果用户使用了自定义的分配器或比较器,但没有正确传递,也可能导致问题。 最后,需要提供具体的代码示例,帮助用户验证他们的实现是否正确。例如,定义一个自定义类型并为其特化std::hash,然后正确声明cuckoohash_map实例,确保没有编译错误。总结,用户的问题核心在于类型不匹配导致的哈希函数无法应用,需要确保键类型与哈希函数期望的类型一致,或者正确提供自定义哈希实现。</think>### 关于libcuckoo::cuckoohash_map的C2664错误解析与解决方法 #### 错误核心 当出现`C2664: "size_t std::hash<std::string>::operator()"`类型转换错误时,根本原因是**键类型与哈希函数模板参数不匹配**。例如: ```cpp // 错误示例:键类型为const char*,但哈希函数期望std::string libcuckoo::cuckoohash_map<const char*, int> invalid_map; // 触发C2664 ``` #### 关键验证步骤 1. **检查键类型一致性** libcuckoo默认使用$std::hash<T>$,需确保键类型$T$满足: - 已包含对应头文件(如$<string>$) - 存在特化的$std::hash<T>$ 2. **自定义类型哈希实现** 若键类型为自定义类$MyKey$,必须实现哈希函数: ```cpp struct MyKey { int id; std::string name; }; namespace std { template<> struct hash<MyKey> { size_t operator()(const MyKey& k) const { // 组合哈希示例 return hash<int>{}(k.id) ^ (hash<string>{}(k.name) << 1); } }; } ``` 3. **显式声明哈希类型** 在容器声明中强制指定哈希函数类型: ```cpp libcuckoo::cuckoohash_map<MyKey, int, std::hash<MyKey>> valid_map; ``` #### 正确使用范式 ```cpp #include <libcuckoo/cuckoohash_map.hh> #include <string> // 必须包含 // 1. 标准类型键 libcuckoo::cuckoohash_map<std::string, int> str_map; // 正确 // 2. 自定义类型键 struct GeoPoint { double lat, lon; }; namespace std { template<> struct hash<GeoPoint> { size_t operator()(const GeoPoint& p) const { return hash<double>{}(p.lat) ^ hash<double>{}(p.lon); } }; } libcuckoo::cuckoohash_map<GeoPoint, std::string> geo_map; // 正确 ``` #### 典型错误修复 ```diff - libcuckoo::cuckoohash_map<char*, int> bad_map; // 错误:未特化哈希 + libcuckoo::cuckoohash_map<std::string, int> good_map; // 正确 ``` #### 性能对比 $$ \text{时间复杂度对比} \begin{cases} \text{std::unordered\_map} & O(1)\text{~}O(n)\\ \text{libcuckoo::cuckoohash\_map} & O(1)\text{~}O(1) \text{(锁分离优化)} \end{cases} $$ libcuckoo通过多哈希表设计减少冲突概率[^1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值