从http://en.cppreference.com/w/cpp/container/unordered_map/unordered_map,unordered_map
可以使用lambda函数进行散列函数。以下答案也是如此:How to use lambda function as hash function in unordered_map?
我的问题是哈希struct
,包括container
,比如说vector
。由于cpprefence
具有以下代码示例
#include <algorithm>
#include <cassert>
#include <string>
#include <unordered_set>
#include <vector>
#include <unordered_map>
using std::hash;
using std::string;
using std::unordered_set;
using std::vector;
int main(int argc, char* argv[]) {
struct Goo {int val; };
auto hash = [](const Goo &g){ return std::hash<int>{}(g.val); };
auto comp = [](const Goo &l, const Goo &r){ return l.val == r.val; };
std::unordered_map<Goo, double, decltype(hash), decltype(comp)> m8(10, hash, comp);
return 0;
}
我修改了它,以便它尝试在vector<int>
中使用Goo
。
#include <algorithm>
#include <cassert>
#include <string>
#include <unordered_set>
#include <vector>
#include <unordered_map>
using std::hash;
using std::string;
using std::unordered_set;
using std::vector;
int main() {
using vint = std::vector<int>;
struct Goo { vint v; };
auto hash = [](const Goo &g){
std::size_t hash_value = 0;
for (const int& i : g.v) {
hash_value ^= std::hash<int>{}(i);
}
return hash_value;
};
auto comp = [](const Goo &l, const Goo &r){
return unordered_set<int>(l.v.begin(), l.v.end()) ==
unordered_set<int>(r.v.begin(), r.v.end());
};
vint here;
std::unordered_map<Goo, double, decltype(hash), decltype(comp)>
m8(here,0, hash, comp);
return 0;
}
此代码无法编译。编译器抱怨不是no matching function for call to ‘std::unordered_map<main(int, char**)::Goo
。参数的数量似乎不是问题,但某些事情必须工作不正确。我非常感谢你的指导。
顺便说一句,我正在使用g ++ -std = c ++ 17。
答案 0 :(得分:1)
我认为你并不理解这个例子。这一行:
std::unordered_map<Goo, double, decltype(hash), decltype(comp)> m8(10, hash, comp);
负责使用至少10个桶创建unordered_map并提供hash和comp函数。它不会创建任何包含10个元素的unordered_map。因此,您的代码应如下所示:
using vint = std::vector<int>;
struct Goo { vint v; };
auto hash = [](const Goo &g){
std::size_t hash_value = 0;
for (const int& i : g.v) {
hash_value ^= std::hash<int>{}(i);
}
return hash_value;
};
auto comp = [](const Goo &l, const Goo &r){
return std::unordered_set<int>(l.v.begin(), l.v.end()) ==
std::unordered_set<int>(r.v.begin(), r.v.end());
};
std::unordered_map<Goo, double, decltype(hash), decltype(comp)>
m8(10, hash, comp);
unordered_map根本就没有任何构造函数可以实现这个:
std::unordered_map<Goo, double, decltype(hash), decltype(comp)>
m8(here, 0, hash, comp);
答案 1 :(得分:0)
我建议使用N3980 Types Don't Know #
中的可组合散列基础结构。它还可以避免容易出错的手动哈希组合。
使用两个成员散列结构的示例,其中一个是向量:
// Hashing infrastructure begin.
class fnv1a
{
std::size_t state_ = 14695981039346656037u;
public:
using result_type = std::size_t;
void operator()(void const* key, std::size_t len) noexcept {
unsigned char const* p = static_cast<unsigned char const*>(key);
unsigned char const* const e = p + len;
for (; p < e; ++p)
state_ = (state_ ^ *p) * 1099511628211u;
}
explicit operator result_type() noexcept {
return state_;
}
};
template<class HashAlgorithm>
struct uhash
{
using result_type = typename HashAlgorithm::result_type;
template <class T>
result_type operator()(T const& t) const noexcept {
HashAlgorithm h;
hash_append(h, t);
return static_cast<result_type>(h);
}
};
template<class HashAlgorithm, class T>
typename std::enable_if<std::is_integral<T>::value>::type
inline hash_append(HashAlgorithm& h, T const& t) noexcept {
h(&t, sizeof t);
}
template<class HashAlgorithm, class T, class... Args>
void hash_append(HashAlgorithm& h, std::vector<T, Args...> const& v) noexcept {
for(auto const& t : v)
hash_append(h, t);
hash_append(h, v.size());
}
template<class HashAlgorithm, class T, class... Args>
void hash_append(HashAlgorithm& h, std::unordered_map<T, Args...> const& v) noexcept {
for(auto const& t : v)
hash_append(h, t);
hash_append(h, v.size());
}
// Hashing infrastructure end
struct Goo
{
std::vector<int> a;
int b;
template<class HashAlgorithm>
friend void hash_append(HashAlgorithm& h, Goo const& v) noexcept {
hash_append(h, v.a);
hash_append(h, v.b);
}
bool operator==(Goo const& other) const {
return a == other.a && b == other.b;
}
};
int main() {
std::unordered_map<Goo, double, uhash<fnv1a>> m;
m[Goo{{1,2,3}, 1}] = 1;
}