《STL源码剖析》的5.7.7 hash function一节中介绍了<stl_hash_fun.h>中定义了数个现成的hash函数,全都是仿函数。这些hash函数支持的模板类型包括:char*, const char*, char, unsigned char, signed char, short, unsigned short, int , unsigned int, long, unsigned long。这些不同类型的hash函数是通过对一下类模板实例化得到的:
template<class T> struct hash { }
大部分内置的hash函数内部并没有做什么,只是返回原值,例如针对short的hash函数如下:
__STL_TEMPLATE_NULL struct hash<short> { size_t operator() (short x) const { return x; } };
对于字符串类型(char *和 const char *),hash函数内部调用了__stl_hash_string,源码如下:
inline size_t __stl_hash_string(const char *s) { unsigned long h = 0; for ( ; *s; ++s) h = 5*h + *s; return size_t(h); } __STL_TEMPLATE_NULL struct hash<char *> { size_t operator() (const char * s) const { return __stl_hash_string(s); } };
由此可见,SGI STL的hashtable无法处理除上述类型以外的元素,例如string, double, float等。也就是说,如果定义unordered_set<string>,并向其中添加string对象时,编译无法通过。因为unordered_set内部使用的就是hashtable,并且没有内置的hash函数来处理string类型。
unordered_set的类定义如下:
template <class Value, class HashFcn = hash<Value>, class EqualKey = equal_to<Value>, class Alloc = alloc> class unordered_set { };
第二个模板参数指明了默认的hash函数,但当Value实例化为string时,找不到相应的hash<string>,编译报错,要想unordered_set支持string,必须为string自定义hash函数。代码如下:
#include <unordered_set> #include <iostream> #include <string> #include <assert.h> using namespace std; template<> //模板实例化 struct hash<string> { size_t operator()(string str) { unsigned long h = 0; for(string::size_type i = 0; i != str.size(); i++) { h = 5*h + str[i]; } return size_t(h); } }; int main () { unordered_multiset<string> ihs; string str; cout << ihs.bucket_count() << endl; ihs.insert(string("abc")); ihs.insert(string("def")); str.assign("kkk"); ihs.insert(str); ihs.insert("abc"); assert(ihs.find(str) != ihs.end()); for(unordered_multiset<string>::iterator it = ihs.begin(); it != ihs.end(); it++) { cout << *it << endl; } system("pause"); }
时间: 2024-11-07 04:35:17