使用STL C ++ hash_map ...
class MyKeyObject
{
std::string str1;
std::string str2;
bool operator==(...) { this.str1 == that.str1 ... }
};
class MyData
{
std::string data1;
int data2;
std::string etcetc;
};
像这样......
MyKeyObject a = MyKeyObject(...);
MyData b = MyData(...);
stdext::hash_map <MyKeyObject, MyData> _myDataHashMap;
_myDataHashMap[ a ] = b;
我得到了一大堆错误。这是前三个......
错误1错误C2784:'布尔 std :: operator&lt;(const 的std :: _树&LT; _Traits&GT; &安培;,const的 的std :: _树&LT; _Traits&GT; &amp;)':不能 推导'const。的模板参数 的std :: _树&LT; _Traits&GT; &安培;”来自'const MyKeyObject'c:\ program files \ microsoft 视觉工作室 8 \ vc \ include \ functional 143
错误2错误C2784:'布尔 std :: operator&lt;(const 的std :: basic_string的&LT; _Elem,_Traits,_Alloc&GT; &amp;,const _Elem *)':无法演绎 'const的模板参数 的std :: basic_string的&LT; _Elem,_Traits,_Alloc&GT; &安培;”来自'const 任务:: MyKeyObject'c:\ program files \ microsoft visual studio 8 \ vc \ include \ functional 143
错误3错误C2784:'布尔 std :: operator&lt;(const _Elem *,const 的std :: basic_string的&LT; _Elem,_Traits,_Alloc&GT; &amp;)':无法推断模板 来自'const _Elem *'的参数 'const MyDataObject'c:\ program files \ microsoft visual studio 8 \ vc \ include \ functional 143
...
如果我将键设置为像int一样简单的东西,那么一切都很好。
我做错了什么?!也许我需要用模板做些什么?
是否有更好(更快?)的方式使用像这样的自定义密钥对象访问数据?
答案 0 :(得分:3)
要使用哈希表,您需要指定哈希函数。您需要创建一个函数对象,该对象表示一个带有MyKeyObject
对象并返回size_t
的函数。然后在最初的大小之后将仿函数作为第二个参数传递:
hash_map <MyKeyObject, MyData> _myDataHashMap(initial_size, YourHashFunctor());
或者,您可以将哈希函数编写为类型的hash<T>
仿函数的模板特化;这样你就不需要传递自定义哈希函数了。
我不知道为什么你会特意得到这些错误。也许它试图将您的对象用作哈希代码或其他什么?在任何情况下,如果没有哈希函数,它都不应该工作。散列函数是为整数类型和字符串预定义的。
答案 1 :(得分:2)
&LT;已删除链接&gt; 清楚地解释了如何使用hash_map并创建自己的哈希函数。
(编辑:已删除链接。现在指向垃圾邮件页面)
答案 2 :(得分:2)
尝试以下操作,在VS 2005中为我工作。这是stdext命名空间中VS2005内置hash_map类型以及boost unordered_map(首选)的解决方案。删除任何不使用的内容。
#include <boost/unordered_map.hpp>
#include <hash_map>
class HashKey
{
public:
HashKey(const std::string& key)
{
_key=key;
}
HashKey(const char* key)
{
_key=key;
}
// for boost and stdext
size_t hash() const
{
// your own hash function here
size_t h = 0;
std::string::const_iterator p, p_end;
for(p = _key.begin(), p_end = _key.end(); p != p_end; ++p)
{
h = 31 * h + (*p);
}
return h;
}
// for boost
bool operator==(const HashKey& other) const
{
return _key == other._key;
}
std::string _key;
};
// for boost
namespace boost
{
template<>
class hash<HashKey>
{
public :
std::size_t operator()(const HashKey &mc) const
{
return mc.hash();
}
};
}
// for stdext
namespace stdext
{
template<>
class hash_compare<HashKey>
{
public :
static const size_t bucket_size = 4;
static const size_t min_buckets = 8;
size_t operator()(const HashKey &mc) const
{
return mc.hash();
}
bool operator()(const HashKey &mc1, const HashKey &mc2) const
{
return (mc1._key < mc2._key);
}
};
}
int _tmain(int argc, _TCHAR* argv[])
{
{
stdext::hash_map<HashKey, int> test;
test["one"] = 1;
test["two"] = 2;
}
{
boost::unordered_map<HashKey, int> test(8); // optional default initial bucket count 8
test["one"] = 1;
test["two"] = 2;
}
return 0;
}
答案 3 :(得分:0)
我用它来映射顶点数据的结构。
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <boost/unordered_map.hpp>
struct VERTEX
{
float x,y,z;
};
typedef boost::unordered_map<std::string, unsigned int> map;
int main()
{
VERTEX v1,v2,v3;
v1.x = 5.0; v1.y = 2.0; v1.z = 2.33333336;
v2.x = 5.0; v2.y = 2.0; v2.z = 2.32333336;
v3.x = 5.0; v3.y = 2.0; v3.z = 2.33333336;
unsigned int vertexSize = sizeof( VERTEX );
char * v1c = new char[vertexSize];
char * v2c = new char[vertexSize];
char * v3c = new char[vertexSize];
memcpy( v1c, &v1, vertexSize );memcpy( v2c, &v2, vertexSize );memcpy( v3c, &v3, vertexSize );
map mymap;
std::string aaa( v1c, vertexSize );
std::string bbb( v2c, vertexSize );
std::string ccc( v3c, vertexSize );
mymap[ aaa ] = 1;
mymap[ bbb ] = 2;
unsigned int a = mymap[ aaa ];
unsigned int b = mymap[ bbb ];
unsigned int c = mymap[ ccc ];
return 0;
}
这只是一个小例子,我如何使用自定义类型。我只是将struct的部分内存复制到char *然后我用第二个param创建字符串,这是大小,大小很重要,因为内存数据可以包含空字符。我不需要任何额外的比较,散列函数......
答案 4 :(得分:0)
在尝试找到相同的答案时,我遇到了这个非常古老的问题,并发现现有的答案并不真正有用。如果我们想要一个哈希映射,现在我们使用unordered_map
,并且让你的MyKeyObject
类可用作hash_map中的键的最佳方法是为类定义一个哈希函数,并告诉它标准库将此哈希函数用于地图。这意味着我们可以在不提供哈希函数的情况下实例化地图模板。
C ++中的wikipedia page&#39;无序关联容器&#39;提供了一个易于理解的示例,我把它简化了一下并将其应用到您的案例中。首先,我们将一个简单的哈希函数定义为成员方法:
#include <functional>
class MyKeyObject {
private:
std::string str1;
std::string str2;
public:
inline size_t hash() const {
return std::hash<std::string>()(str1) ^ std::hash<std::string>()(str2);
}
inline bool operator==(const MyKeyObject& other) const {
return str1 == other.str1 && str2 == other.str2;
}
};
为了制作哈希函数,我们将所有包含对象的哈希值合并在一起。这是使用std::hash
完成的,MyKeyObject
是一个必须用子类型实例化的模板。请注意,我们不能将其用作unordered_map的第三个模板参数。另请注意const-equals运算符。
现在我们必须告诉标准库这是用于namespace std {
template <>
class hash<MyKeyObject> {
public:
size_t operator()(const MyKeyObject &aMyKeyObject) const {
return aMyKeyObject.hash();
}
};
}
值的哈希函数:
std::hash
这为MyKeyObject
模板类添加了模板特化,为MyKeyObject
类提供了哈希运算符。这个例子没有维基百科页面直接在这里定义哈希,而不是调用作为对象成员的哈希函数 - 但是如果哈希函数必须访问私有成员,那么它将无法工作。
现在,您应该可以在unordered_map
中使用 std::unordered_map<MyKeyObject, MyData> _myDataHashMap;
,如此:
{{1}}
(使用clang / xcode测试)