unordered_map的用户定义散列函数

时间:2017-05-12 07:40:17

标签: c++ hash stl unordered-map

我正在尝试在stl unordered_map上创建一个模板化的包装类。我将散列函数类作为模板参数传递给包装器类,并提供了字符串特化。下面的代码编译并工作,但如果包含注释部分,则编译错误说:

  

“/ usr / include / c ++ / 6 / bits / unordered_map.h:143:28:错误:没有匹配   调用'HashFunction

的函数      
    

::散列函数()”            const hasher& __hf = hasher(),“。

  

但是,我必须拥有哈希函数类的ctor。我试过各种方法,但无法使其发挥作用。请提供您的想法/意见。

#include <iostream>
#include <unordered_map>
using namespace std;

template< class Key >
class HashFunction
{
  public:
    //HashFunction( const Key & inKey );
    size_t operator()(const Key &inKey) const;
  private:
    unsigned mHashCode;
};

//template<>
//HashFunction< string >::HashFunction( const string & inKey )
//{
    //mHashCode=std::hash<string>{}(inKey);
//}

template <> 
size_t HashFunction< string >::operator()(const string &inKey) const 
{
  return std::hash<string>{}(inKey);
  //return mHashCode;
}

template< class Key, class Val, class Hash = HashFunction< Key > >
class unordered_map_wrapper
{
  public:
   unordered_map_wrapper();
  private:
    unordered_map<Key, Val, Hash> * mTable;
};

template< class Key, class Val, class Hash >
unordered_map_wrapper< Key, Val, Hash >::unordered_map_wrapper()
{
    mTable=new unordered_map<Key, Val, Hash>(10);
}

int main() {
    unordered_map_wrapper<string, unsigned> h;
    return 0;
}

2 个答案:

答案 0 :(得分:1)

它希望有一个默认构造函数,在您定义自定义版本时会将其删除。

编译:

template< class Key >
class HashFunction
{
public:
    HashFunction(){};
    HashFunction( const Key & inKey );
    size_t operator()(const Key &inKey) const;
private:
    unsigned mHashCode;
};

答案 1 :(得分:1)

这不是Hash模板参数在unordered_map中的工作方式!该映射创建一个单独的Hash实例(使用默认构造函数,因此您需要提供它!),该实例用于进一步需要的所有哈希计算。所以你的班级必须是这样的:

template<class Key>
class HashFunction
{
public:
    // HashFunction(); <- can just leave it out...
    size_t operator()(const Key& inKey) const;
};

template<>
size_t HashFunction<std::string>::operator()(const std::string& inKey) const
{
    // calculate hash value in operator!!!
    return std::hash<std::string>()(inKey);
}

为了避免一直构造std :: hash,我宁愿专门研究整个模板类:

template<class Key>
class HashFunction; // leave entirely unimplemented
                    // (if it has no general meaning, at least...)

template<>
class HashFunction<std::string>
{
public:
    size_t operator()(const std::string& inKey) const
    {
        return mHash(inKey);
    }
private:
    std::hash<std::string> mHash;
};

重新实现已经存在的东西没有多大意义。我可以假设你在这里使用std :: string作为你自己班级的占位符吗?

顺便说一下:一个简单的typedef比你的包装类更容易完成工作:

template <typename Key, typename Value>
using my_unordered_map = std::unordered_map<Key, Value, HashFunction<Key>>;

也许您对替代品感兴趣?让我们首先假设您有两个类(而不是std :: string):

class C1
{ };
class C2
{ };

最优雅的解决方案(至少在我看来)只是为你的类专门化std :: hash(一般来说,向std命名空间添加一些东西是非法的,模板特化是例外......):

namespace std
{
template<>
class hash<C1>
{
public:
    size_t operator()(C const& c) const
    {
        return 0; // your implementation here...
    }
};
// same for C2
}

// no typedef necessary, just use std::unordered_map directly:
std::unordered_map<C1, unsigned> m1;
std::unordered_map<C2, unsigned> m2;

您可以提供自己的HashFunction类,提供重载

class HashFunction
{
public:
    size_t operator()(C1 const& c) const
    {
        return 0;
    }
    size_t operator()(C2 const& c) const
    {
        return 0;
    }
};

同样,typedef让您的生活更轻松:

template <typename Key, typename Value>
using my_unordered_map = std::unordered_map<Key, Value, HashFunction>;

std::unordered_map<C1, unsigned, HashFunction> m1;
my_unordered_map<C1, unsigned> m1_;

std::unordered_map<C2, unsigned, HashFunction> m2;
my_unordered_map<C2, unsigned> m2_;

最后,如果绝对需要使用一些参数初始化HashFunction以正确配置它,那么可以这样做,但您必须提供预先配置的实例那么你的哈希映射!

template<typename T>
class HashFunction
{
public:
    HashFunction(double value);
    size_t operator()(T const& c) const;
private:
    double data;
};

template<typename T>
HashFunction<T>::HashFunction(double value)
        : data(value)
{ }

template<>
size_t HashFunction<C1>::operator()(C1 const& c) const
{
    return static_cast<size_t>(data);
};
template<>
size_t HashFunction<C2>::operator()(C2 const& c) const
{
    return static_cast<size_t>(data);
};

template <typename Key, typename Value>
using my_unordered_map = std::unordered_map<Key, Value, HashFunction<Key>>;

my_unordered_map<C1, unsigned> m1(12, HashFunction<C1>(10.12));
my_unordered_map<C2, unsigned> m2(10, HashFunction<C2>(12.10));

嗯,现在,至少,你的包装类可以再次派上用场了:

template <typename Key, typename Value, typename Hash = HashFunction<Key>>
class unordered_map_wrapper
{
public:
    unordered_map_wrapper()
        : mMap(16, Hash())
    { }
    unordered_map_wrapper(double parameter)
        : mMap(16, Hash(parameter))
    { }
private:
    std::unordered_map<Key, Value, Hash> mMap;
};

unordered_map_wrapper<C1, unsigned> m1(10.12);
unordered_map_wrapper<C2, unsigned> m2(12.10);
// possible due to provided default ctor:
unordered_map_wrapper<std::string, unsigned, std::hash<std::string>> m3;