c++ - 使 std 的数据结构默认使用我现有的非静态哈希函数 "hashCode()"

标签 c++ c++11 templates hash sfinae

我有一个中等大小的代码库 (>200 .cpp),它使用函数 hashCode() 返回哈希值:-

class B01{  //a class
    //..... complex thing ....
    public: size_t hashCode(){ /* hash algorithm #H01 */}  
};
class B02{  //just another unrelated class
    //..... complex thing ....
    public: size_t hashCode(){/* #H02 */}  //This is the same name as above
};

我已经在不同的地方使用过它,例如在我的自定义数据结构中。它运行良好。

现在,我想让std::数据结构识别的hash算法:-

这是我应该做的:-(修改自 cppreference ,我将此代码称为 #D)。

//#D
namespace std {
    template<> struct hash<B01> {
        std::size_t operator()(const B01& b) const {
            /* hash algorithm #H01 */
        }
    };
}

如果我在每个类(B01B02、...)中插入 block #D(具有适当的实现),我可以打电话:-

std::unordered_set<B01> b01s;
std::unordered_set<B02> b02s;

传递第二个模板参数,
我的哈希算法 (#H01) 将被调用。 (按默认)

问题

让它识别我所有的B01::hashCode, B02::hashCode, ...,
我是否必须将 block #D 插入到所有 200 多个 Bxx.h 中?

我可以只添加一个单个 block #D(在顶部标题中吗?)
并从那里重新路由 std::anyDataStructure 以尽可能调用hashCode()

//pseudo code
namespace std{
    template<> struct hash<X>   {
        std::size_t operator()(const X& x) const { // std::enable_if??
            if(X has hashCode()){    //e.g. T=B01 or B02       
                make this template highest priority   //how?
                return hashCode();
            }else{                   //e.g. T=std::string
                don't match this template;  
            }
        }
    };
}

对我来说这听起来像是一个 SFINAE 问题。

旁注: The most similar question在 SO 中没有询问如何实现这一点。

编辑(我为什么不直接重构它?;2017 年 2 月 3 日)

  • 我不知道强力重构是否是一条正确的道路。我想可能有更好的方法。
  • hashCode() 是我的家。我在情感上依恋它。
  • 我希望我的代码尽可能简洁明了。 std:: block 是脏的。
  • 这可能只是我的好奇心。如果我固执地不重构我的代码,C++ 能走多远?

最佳答案

不一定非要这样,你也可以有一个仿函数:

struct MyHash {
    template <class T>
    auto hashCode(const T & t, int) const -> decltype(t.hashCode()) {
        return t.hashCode();
    }
    template <class T>
    auto hashCode(const T & t, long) const -> decltype(std::hash<T>{}(t)) {
        return std::hash<T>{}(t);
    }
    
    template <class T>
    auto operator()(const T & t) const -> decltype(hashCode(t,42)) {
        return hashCode(t,42);
    }
};

并且有一个 std::unordered_set 的别名,MyHash 作为散列类型:

template <class Key>
using my_unordered_set = std::unordered_set<Key, MyHash>;

如果您还希望能够提供 Equal 仿函数和分配器,则可以更完整:

template<
    class Key,
    class KeyEqual = std::equal_to<Key>,
    class Allocator = std::allocator<Key>
>
using my_unordered_set = std::unordered_set<Key, MyHash, KeyEqual, Allocator>;

然后像使用 std::unordered_set 一样使用它(与任何 Bxx):

int main() {
    my_unordered_set<B01> b01s;
    my_unordered_set<B02> b02s;

    // or lonely with your type:
    B01 b01{/*...*/};
    std::cout << MyHash{}(b01) << std::endl;

    // or any other:
    std::string str{"Hello World!"};
    std::cout << MyHash{}(str) << std::endl;
}

概念

如果可以使用concepts ,它们可以让你按照你想要的方式专门化 std::hash 类:

template <class T>
concept HashCodeConcept = requires(T const & t)
{
    {t.hashCode()} -> std::same_as<std::size_t>;
};

namespace std {
    template <HashCodeConcept T>
    struct hash<T> {
        std::size_t operator()(const T& t) const {
            return  t.hashCode();
        }
    };
}

关于c++ - 使 std 的数据结构默认使用我现有的非静态哈希函数 "hashCode()",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41867111/

相关文章:

c++ - 编写 lambda 函数 vector 时出现段错误

regex - C++ regex_search() 不适用于星号量词

c++ - 如果可能,取消对 C++ 类型指针的引用

c++ - 为什么不将模板类型参数推断为 'const' ?

c++ - 如何使用 C++ 在 Linux 中获取 utc 偏移量

c++ - 为什么可变函数模板常量中的这个 constexpr 不是常量?

c++ - 非命名空间范围的显式特化

c++ - 如何使用在命名空间中声明的类实例的 vector

c++ - 由于固定大小的成员而导致的 Eigen 运行时断言

C++强制覆盖