C++ 函数指针表的哈希专门化

C++ 函数指针表的哈希专门化,c++,templates,hash,C++,Templates,Hash,以粗体显示的更新 我正在为函数指针表编写一个哈希函数,但函数指针和函数表的结构不能修改,即它们已发布给第三方。基于,std::hash可用于函数指针。采用该方法,它将产生以下解决方案 这个解决方案的乏味之处在于,每次我们向FuncPointers结构添加新的API时,我们都必须修改哈希专门化以添加相应的更改,即hashFunchashedValue、pFuncs->func3 我想知道是否有更好的方法来实现函数指针的散列,从而避免对散列专门化的持续修改 typedef void (*func_t

以粗体显示的更新

我正在为函数指针表编写一个哈希函数,但函数指针和函数表的结构不能修改,即它们已发布给第三方。基于,std::hash可用于函数指针。采用该方法,它将产生以下解决方案

这个解决方案的乏味之处在于,每次我们向FuncPointers结构添加新的API时,我们都必须修改哈希专门化以添加相应的更改,即hashFunchashedValue、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;
        }
    };
}

最好将funcpointer设置为std::tuple。然后看散列

BTW,StutsFuxFraseFoxPoeNeX { FuncPointers是C++中从来没有必要的C-ISM。

< P>从这里开始:

它提供了一个hash_tuple::hash,它是一个有效的、高质量的散列器,支持组合和递归!对于std::tuple

接下来,按如下方式更改FuncPointer:

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);
    }
  };
}
这会将funcPointers.func1更改为funcPointers.func,但在添加新func时会删除大量样板文件,并且与funcPointers的旧接口非常相似

如果没有太多使用旧接口的代码,那么使用std::get会有一些意义


如果您的名称比func1更具描述性,并且仅在示例中使用了该名称,则函数名称的枚举可以与上面的std::get或func一起使用。如果使用func,甚至可以使其类型安全,强制使用命名函数。

为std::tuple专门化哈希是未定义的行为。链接的答案使用对称的^,这在散列时是一个坏主意。@Yakk:我没有说你应该专门化std::hash,只是提供你自己的散列作为std::unordered_集的第二个参数。你是对的,plain^是一个坏主意,但是链接答案的相关想法是枚举元组成员。OP专门介绍std::hash-用std::tuple替换funcpointer使这不可能很好,可能,但不再合法!。您链接到的答案专门针对std::hash,这是一种不需要诊断的未定义行为,更糟糕的情况通常有效。我只是说,你的答案会导致OP或其他人一次以2-3种不同的方式阅读错误的路径。下面是一个符合标准的std::tuple解决方案:答案的第二部分,第一部分违反了C++11标准。我没有提到我的缺点的一个限制是,我无法更改函数指针的结构以及函数表,即这些结构已经发布给第三方,因此我们无法修改它们。我会仔细看看你的建议,看看我是否可以用这个限制来合理化它。@lancery你可以编写一个get_tie方法,将每个变量包装成std::tie,这与手动维护散列的代码大致相同,或者你可以等待反射的到来,可能在C++17之前。静态_断言您处理的函数数量*sizeof function pointer==sizeofFuncPointers可能很有用。由于这是一个函数指针表,我们能否简化假设它们都是相同大小的,即通过使用size_t并以某种方式对其进行迭代?@lancery auto begin=reinterpret_cast&fp;自动结束=开始+sizeoffp/SizeOffoid常量*;然后,范围上的累积哈希是否开始结束?危险包括:成员之间的填充物,前面的额外垃圾,最后的额外垃圾或填充物。我们可以通过一些匿名的结构和联合操作来减少这种奇怪的情况——愿意限制您使用的编译器吗?这是使用VC++编译器编译的。我们需要担心填充物吗?我的理解是,由于它是一个直接的结构定义,而不是成员结构,所以不必担心胖指针,函数指针是4字节或8字节,所以它们自然对齐。
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); }