c ++ 11多态映射键静态断言失败:哈希函数必须可通过键类型的参数调用

时间:2019-03-13 10:41:43

标签: c++ c++11 std

错误是

in file included from /usr/include/c++/8/unordered_map:46,
                from main.cpp:3:
/usr/include/c++/8/bits/hashtable.h: In instantiation of ‘class std::_Hashtable<MyClass*, std::pair<MyClass* const, double>, std::allocator<std::pair<MyClass* const, double> >, std::__detail::_Select1st, MyClassEquality, MyClassHash, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<true, false, true> >’:
/usr/include/c++/8/bits/unordered_map.h:105:18:   required from ‘class std::unordered_map<MyClass*, double, MyClassHash, MyClassEquality>’
main.cpp:35:68:   required from here
/usr/include/c++/8/bits/hashtable.h:195:21: error: static assertion failed: hash function must be invocable with an argument of key type
    static_assert(__is_invocable<const _H1&, const _Key&>{},
                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/8/bits/hashtable.h:197:21: error: static assertion failed: key equality predicate must be invocable with two arguments of key type
    static_assert(__is_invocable<const _Equal&, const _Key&, const _Key&>{},
                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

代码是

#include <iostream>
#include <functional>
#include <unordered_map>

using namespace std;

class MyClass {
public:
    long my_id;

    MyClass() {
        my_id = lrand48();
    }

    size_t id() const {
        hash<long> long_hash;
        return long_hash(my_id);
    }
};

struct MyClassHash {
public:
    size_t operator() (const MyClass * &c) const {
        return c->id();
    }
};

struct MyClassEquality {
public:
    bool operator() (const MyClass * &a, const MyClass * &b) const {
        return a->id() == b->id();
    }
};

class TestClass {
public:
    unordered_map<MyClass *, double, MyClassHash, MyClassEquality> my_map;;

/* makes no difference
 * TestClass() {
 *        my_map = unordered_map<MyClass *, double, MyClassHash, MyClassEquality>(42, MyClassHash(), MyClassEquality());
 *    }
 */

    void test() {
        for (auto p : my_map) {
            cout << p.first << "," << p.second << endl;
        }
    }
};

int main(int argc, char * argv[]) {
    auto * a = new TestClass();
    a->test();
    return 0;
}

映射具有指针作为键的原因是程序在与映射的内容进行交互时需要利用多态性;代码中是否存在相对简单的监督,还是有更合适的设计模式?

我尝试了一些变体,例如将struct更改为class,而不声明哈希/等价运算符public等。类似地,注释的构造函数。

1 个答案:

答案 0 :(得分:1)

鉴于使用多态指针作为映射键的一般设计模式看起来似乎没有什么特别有用的结果,因此我将正确且非常快速地将修改后的代码发布为rafix07建议

struct MyClassHash {
public:
    size_t operator() (const MyClass * c) const {
        return c->id();
    }
};

struct MyClassEquality {
public:
    bool operator() (const MyClass * a, const MyClass * b) const {
        return a->id() == b->id();
    }
};