我想在地图中使用POD结构作为哈希键,例如
struct A { int x; int y; };
std::unordered_map<A, int> my_map;
但是我不能这样做,因为没有哈希函数可以自动生成这样的结构。
答案 0 :(得分:3)
从documentation开始,您的案例中可能的实施方式是:
#include<functional>
#include<unordered_map>
struct A { int x; int y; };
namespace std
{
template<> struct hash<A>
{
using argument_type = A;
using result_type = std::size_t;
result_type operator()(argument_type const& a) const
{
result_type const h1 ( std::hash<int>()(a.x) );
result_type const h2 ( std::hash<int>()(a.y) );
return h1 ^ (h2 << 1);
}
};
}
int main() {
std::unordered_map<A, int> my_map;
}
编译器不允许生成这样的专门化,因为标准没有定义类似的东西(如评论中已经提到的那样)。
答案 1 :(得分:1)
有一种为POD生成哈希的方法,就像好的旧c
样式一样。仅适用于结构外部没有任何链接数据的真实POD。代码中没有检查此要求,因此只有在您知道并且可以保证这一点时才使用它。必须初始化所有字段(例如,默认构造函数,如此A(),B()等)。
#pragma pack(push) /* push current alignment to stack */
#pragma pack(1) /* set alignment to 1 byte boundary */
struct A { int x; int y; };
struct B { int x; char ch[8] };
#pragma pack(pop) /* restore original alignment from stack */
struct C { int x __attribute__((packed)); };
template<class T> class PodHash;
template<>
class PodHash<A> {
public:
size_t operator()(const A &a) const
{
// it is possible to write hash func here char by char without using std::string
const std::string str =
std::string( reinterpret_cast<const std::string::value_type*>( &a ), sizeof(A) );
return std::hash<std::string>()( str );
}
};
std::unordered_map< A, int, PodHash<A> > m_mapMyMapA;
std::unordered_map< B, int, PodHash<B> > m_mapMyMapB;
UPD: 必须在数据打包部分中定义数据结构,其值为一个字节或使用pack属性以防止填充字节。
UPD: 但我需要警告的是,替换deafult包装会使某些字段的数据加载/存储到某些字段的速度很慢,以防止需要按照与您(或最常用)体系结构相对应的粒度排列结构数据字段。
我建议你可以自己添加其他未使用的字段,而不是用于数据结构中的排列字段,以便最好地记录内存加载/存储。例如:
struct A
{
char x; // 1 byte
char padding1[3]; // 3 byte for the following 'int'
int y; // 4 bytes - largest structure member
short z; // 2 byte
char padding2[2]; // 2 bytes to make total size of the structure 12 bytes
};
至少支持 #pragma pack
:
答案 2 :(得分:0)
更灵活的方法是声明比较类并将其用作std::unordered_map
的模板参数。
struct A { int x; int y; };
emplate<class T> class MyHash;
template<>
class MyHash<A> {
public:
size_t operator()(const A &a) const
{
result_type const h1 ( std::hash<int>()(a.x) );
result_type const h2 ( std::hash<int>()(a.y) );
return h1 ^ (h2 << 1);
}
};
std::unordered_map<CString,CString,MyHash> m_mapMyMap;
您可能需要另一个Hash用于相同的对象。灵活性出现在这样的代码中:
std::unordered_map<CString,CString, *MyAnotherHas* > m_mapMyMap;