如何通过传递命名函数为 unordered_set 显式指定自定义哈希函数?
How do I specify a custom hash function explicitly for unordered_set by passing a named function?
根据 this question 的公认答案,可以使用 std
的特化来为用户定义的类型提供哈希函数。
#include <unordered_set>
#include <stdint.h>
struct FooBar {
int i;
};
namespace std {
template <> struct hash<FooBar>
{
size_t operator()(const FooBar & x) const
{
return x.i;
}
};
}
int main(){
std::unordered_set<FooBar> foo(0);
}
然而,documentation似乎暗示自定义哈希函数也可以显式传递给构造函数,我想为这个哈希函数使用命名函数。
但是,我目前的尝试遇到了编译错误。
#include <unordered_set>
#include <stdint.h>
struct FooBar {
int i;
};
const size_t hashFooBar(const FooBar& foo) {
return foo.i;
}
int main(){
std::unordered_set<FooBar> foo(0, hashFooBar);
}
使这项工作有效的正确模板魔术和方法签名是什么?
您需要提供哈希器的类型,在您的例子中是函数指针。并且您的 FooBar
类型必须是相等的可比较的。或者等效地,您可以使用与提供散列器相同的方式提供相等谓词。
#include <unordered_set>
#include <stdint.h>
struct FooBar {
int i;
};
bool operator==(const FooBar& x, const FooBar& y)
{
return x.i == y.i;
}
size_t hashFooBar(const FooBar& foo) {
return foo.i;
}
int main(){
std::unordered_set<FooBar, size_t(*)(const FooBar&)> foo(0, hashFooBar);
}
我还应该指出,提供 "functor" 而不是函数更受欢迎,因为前者可以内联,而后者可能不会内联。
#include <unordered_set>
#include <stdint.h>
struct FooBar {
int i;
};
bool operator==(const FooBar& x, const FooBar& y)
{
return x.i == y.i;
}
struct hashFooBar
{
size_t operator()(const FooBar& foo) const {
return foo.i;
}
};
int main(){
std::unordered_set<FooBar, hashFooBar> foo(0);
}
除了,它解释了如何传入一个函数指针和一个自定义首选(后者严格首选),你也可以像这样传入一个lambda:
bool operator==(const FooBar& x, const FooBar& y)
{
return x.i == y.i;
}
int main() {
auto hash = [](const FooBar& foo) { return foo.i; };
std::unordered_set<FooBar, decltype(hash)> set{0, hash};
}
这也可能会内联哈希函数,而函数指针版本肯定不会。您还可以通过打印尺寸来查看:
std::unordered_set<FooBar, decltype(hash)> setLambda{0, hash};
std::unordered_set<FooBar, int(*)(const FooBar&)> setFuncPtr{0, +hash};
std::cout << sizeof(setLambda); // prints 56
std::cout << sizeof(setFuncPtr); // prints 64, cause of the
// extra function pointer
根据 this question 的公认答案,可以使用 std
的特化来为用户定义的类型提供哈希函数。
#include <unordered_set>
#include <stdint.h>
struct FooBar {
int i;
};
namespace std {
template <> struct hash<FooBar>
{
size_t operator()(const FooBar & x) const
{
return x.i;
}
};
}
int main(){
std::unordered_set<FooBar> foo(0);
}
然而,documentation似乎暗示自定义哈希函数也可以显式传递给构造函数,我想为这个哈希函数使用命名函数。
但是,我目前的尝试遇到了编译错误。
#include <unordered_set>
#include <stdint.h>
struct FooBar {
int i;
};
const size_t hashFooBar(const FooBar& foo) {
return foo.i;
}
int main(){
std::unordered_set<FooBar> foo(0, hashFooBar);
}
使这项工作有效的正确模板魔术和方法签名是什么?
您需要提供哈希器的类型,在您的例子中是函数指针。并且您的 FooBar
类型必须是相等的可比较的。或者等效地,您可以使用与提供散列器相同的方式提供相等谓词。
#include <unordered_set>
#include <stdint.h>
struct FooBar {
int i;
};
bool operator==(const FooBar& x, const FooBar& y)
{
return x.i == y.i;
}
size_t hashFooBar(const FooBar& foo) {
return foo.i;
}
int main(){
std::unordered_set<FooBar, size_t(*)(const FooBar&)> foo(0, hashFooBar);
}
我还应该指出,提供 "functor" 而不是函数更受欢迎,因为前者可以内联,而后者可能不会内联。
#include <unordered_set>
#include <stdint.h>
struct FooBar {
int i;
};
bool operator==(const FooBar& x, const FooBar& y)
{
return x.i == y.i;
}
struct hashFooBar
{
size_t operator()(const FooBar& foo) const {
return foo.i;
}
};
int main(){
std::unordered_set<FooBar, hashFooBar> foo(0);
}
除了
bool operator==(const FooBar& x, const FooBar& y)
{
return x.i == y.i;
}
int main() {
auto hash = [](const FooBar& foo) { return foo.i; };
std::unordered_set<FooBar, decltype(hash)> set{0, hash};
}
这也可能会内联哈希函数,而函数指针版本肯定不会。您还可以通过打印尺寸来查看:
std::unordered_set<FooBar, decltype(hash)> setLambda{0, hash};
std::unordered_set<FooBar, int(*)(const FooBar&)> setFuncPtr{0, +hash};
std::cout << sizeof(setLambda); // prints 56
std::cout << sizeof(setFuncPtr); // prints 64, cause of the
// extra function pointer