我有一个中等大小的代码库 (>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 */
}
};
}
如果我在每个类(B01
、B02
、...)中插入 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/