函数指针表的哈希特化

时间:2014-05-14 09:15:01

标签: c++ templates hash

粗体

中的更新

我正在为函数指针的表编写一个哈希函数,其限制是函数指针和函数表的结构不能被修改(即它们已经发布给第三方)。基于Can std::hash be used to hash function pointers?,std :: hash可用于函数指针。采用它,它产生以下解决方案。

关于这个解决方案的繁琐部分是每次我们向FuncPointers结构添加新的API时,我们必须修改哈希特化以添加相应的更改(即hashFunc(hashedValue,pFuncs-> func3))

我想知道是否有更好的方法来实现函数指针的散列,因此可以避免对散列特化的连续修改?

typedef void (*func_type1) (int);
typedef void (*func_type2) (double);

typedef struct FuncPointers
{
    func_type1 func1;
    func_type2 func2;
    ...
} FuncPointers;

template <typename T> void hashFunc (size_t & HashedValue, T funcPointer)
{
    std::hash<T> hash;
    HashedValue ^= hash(funcPointer); // the XOR operator is randomly picked
}

namespace std
{
    template<> struct hash<FuncPointers>
    {
        size_t operator()(FuncPointers *pFuncs)
        {
            size_t hashedValue = 0;
            hashFunc(hashedValue, pFuncs->func1);
            hashFunc(hashedValue, pFuncs->func2);
            ...

            return hashedValue;
        }
    };
}

2 个答案:

答案 0 :(得分:0)

从这开始:https://stackoverflow.com/a/7115547/1774667

它为hash_tuple::hash<Tuple>提供了std::tuple,它是一个有效的体面质量哈希(具有组合和递归支持!)。

接下来,按如下方式更改FuncPointers

struct FuncPointers:std::tuple<func_type1, func_type2 /*, ...*/> {

  // optional:
  func_type1 func1() const { return std::get<0>(*this); }
  func_type1& func1() { return std::get<0>(*this); }
  //...
};
namespace std {
  template<>
  struct hash<FuncPointers> {
    template<typename... Ts>
    std::size_t operator()( std::tuple<Ts...> const& funcs ) const {
      return hash_tuple::hash<std::tuple<Ts...>>{}(funcs);
    }
  };
}

重定向std::hash<FuncPointers>以在hash_tuple::hash<std::tuple<...>>的父级上调用FuncPointers。如果您不想继承std::tuple,则将其更改为has-a而不是is-a关系应该很容易。

可选的func()访问器使您更接近旧界面(只需添加()),但也添加了样板。

另一种选择是:

template<unsigned N>
auto func() const->decltype( std::get<N>(*this) ){ return std::get<N>(*this); }
template<unsigned N>
auto& func()->decltype( std::get<N>(*this) ){ return std::get<N>(*this); }

funcPointers.func1更改为funcPointers.func<1>(),但在添加新的func时会删除大量的样板,并且与funcPointers的旧接口保持非常相似。

如果使用旧界面的代码不多,则使用std::get<N>()会有所帮助。

如果您的名称比func1更具描述性,并且您仅将其用于示例,则函数名称的枚举可以与上面的std::getfunc<X>一起使用。如果你使用func<X>,你甚至可以使它类型安全(强制使用命名函数)。

答案 1 :(得分:-1)

最好不要让FuncPointers成为std::tuple<func_type1, func_type2>。然后在散列上查看this answer

BTW,typedef struct FuncPointers { } FuncPointers是一个C-ism,在C ++中从来就不是必需的。