C++ unordered_map使用自定义键类型
unordered_map定义(C++11)
template< class Key, class T, class Hash = std::hash<Key>, class KeyEqual = std::equal_to<Key>, class Allocator = std::allocator< std::pair<const Key, T> > > class unordered_map;
Key代表键值(key),T是根据哈希函数得到的值(value),Hash是哈希函数的函数对象,KeyEqual是等比函数的函数对象,通过"=="
来判断两个key是否相等。想使用自定义的键类型,必须实现hash函数和等比函数。
实现
- 法一:利用std::function中的默认hash函数std::hash
#include <functional> #include <unordered_map> class mypair { public: char first; char second; mypair(char a, char b) { if( a < b) { first = a; second = b; } else { first = b; second = a; } } bool operator==(const mypair& rhs) { return rhs.first == this->first && rhs.second == this->second; } }; static size_t mypair_hash(const mypair& tmp) { return hash<char>()(tmp.first) ^ hash<char>()(tmp.second); } int main() { //ERRO: unordered_map<mypair, int, decltype(&mypair_hash)> ids; //ERRO: unordered_map<mypair, int, mypair_hash> ids(100, mypair_hash ); //OK: unordered_map<mypair, int, decltype(&mypair_hash)> ids(100, mypair_hash ); unordered_map<mypair, int, decltype(&mypair_hash)> memo(20/*, mypair_hash*/); //在这里decltype后面必须要使用引用 /* * code */ }
Note:
1) decltype(exp)推导的内容如果是一个左值,那么 decltype(exp) 的类型就是 exp 的引用。在这里mypair_hash是一个函数,如果是自动推导得到的是函数的返回值,不是引用类型,运行时编译器会报错,在hashtable_policy.h中:field 'std::__detail::_Hashtable_ebo_helper<1, long long unsigned int(const mypair&), false>::_M_tp' invalidly declared function type
2) 参考的博客中说memo初始化时必须传入mypair_hash构造函数,但是我尝试不传入发现也是可以编译通过和运行的。
- 法二:重载operator()类,打包哈希函数变成函数对象
class mypair { public: char first; char second; mypair(const char& a, const char& b) { first = a; second = b; } bool operator==(const mypair& rhs) const { return rhs.first == first && rhs.second == second; } }; struct hashname { size_t operator()(const mypair& tmp) const { return (hash<char>()(tmp.first)) ^ (hash<char>()(tmp.second)); } }; int main() { unordered_map<mypair, int, hashname> memo(20); /* * code */ }
可以直接运行通过,没有什么坑。