在unordered_map中使用lambda函数进行散列<vector <t>&gt;

时间:2017-10-31 15:52:39

标签: c++ hash lambda

http://en.cppreference.com/w/cpp/container/unordered_map/unordered_mapunordered_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。

2 个答案:

答案 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;
}