函数指针表的哈希专用化



>以粗体显示更新

我正在为函数指针表编写一个哈希函数,其限制是函数指针和函数表的结构无法修改(即它们已发布给第三方(。基于std::hash 可以用于哈希函数指针吗?,std::hash 可用于函数指针。采用它,它会产生以下解决方案。

这个解决方案的乏味之处在于,每次我们向 FuncPointer 结构添加新的 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;
        }
    };
}

从这个开始: 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>重定向到在FuncPointers的父级上调用hash_tuple::hash<std::tuple<...>>。 如果您不想从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>你甚至可以让它类型安全(强制使用命名函数(。

最好让你的FuncPointers成为std::tuple<func_type1, func_type2>。然后看到这个关于哈希的答案。

顺便说一句,typedef struct FuncPointers { } FuncPointers是一种在C++中从来不需要的C主义。

最新更新