如何通过传递命名函数为unordered_set显式指定自定义哈希函数?

时间:2015-01-24 00:24:38

标签: c++ c++11 hash

根据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);
}

使这项工作正确的模板魔术和方法签名是什么?

2 个答案:

答案 0 :(得分:6)

您需要提供哈希的类型,在您的情况下是一个函数指针。并且您的FooBar类型必须具有可比性。或者等效地,您可以以与提供hasher相同的方式提供等式谓词。

#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);
}

我还应该注意,提供“仿函数”而不是函数更受欢迎,因为前者可以内联,而后者可能不会内联。

#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);
}

答案 1 :(得分:1)

除了Howard Hinnant's answer,它解释了如何传入函数指针和自定义首选(后者严格优先),你也可以像这样传入一个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};
}

这也可能会内联散列函数,而函数指针版本肯定会赢得#t; t。您还可以通过打印尺寸来看到:

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