我正在尝试将 std::unordered_map 专门化为具有自定义散列和自定义相等性的类 X。问题是相等函数和哈希函数不仅依赖于类 X 的对象,还依赖于另一个类 Y 的另一个(固定)对象中的数据。这是一个玩具示例(仅具有哈希函数)我想做的事情:
#include <unordered_map>
using namespace std;
struct Y {
bool b;
struct X {
size_t i;
};
size_t hash(const X &x) {
return x.i + b;
}
unordered_map<X, int, hash> mymap;
};
问题是模板特化中的函数散列是一个方法,编译器会提示(“调用没有对象参数的非静态成员函数”)。我想要的是 y.mymap 使用 y.hash()。有什么办法吗?
请注意,在实际代码中,Y 也是一个模板,以防万一。
谢谢!
编辑:为了澄清,我的代码中没有 bool 值 b,而是有一个 vector ,其中包含比较 X 类型对象所需的数据。创建 X 时会添加一些数据,因此 vector 不是常量,但是给定 X 的数据在添加后不会改变,因此给定 X 的散列永远不会改变(因此在某种意义上它仅取决于散列所需的 X)。我使用这种方法的主要原因是为了节省内存,因为这些数据很多而且通常是共享的。
最佳答案
您可以使用 function<size_t(X const&)>
和例如bind
, 但由于在这种情况下不需要类型删除,这里有一个更简单的解决方案:
struct Y {
bool b;
struct X {
size_t i;
bool operator==(X x) const {return i == x.i;}
};
size_t hash(const X &x) {
return x.i + b;
}
struct Hasher {
Y* this_;
template <typename T>
auto operator()(T&& t) const
-> decltype(this_->hash(std::forward<T>(t))) {
return this_->hash(std::forward<T>(t));
}
};
unordered_map<X, int, Hasher> mymap;
Y() : b(false),
mymap(0, {this}) {}
};
正如@dyp 在评论中提到的,您必须小心特殊的成员函数,因为我们隐式存储了 this
。在 mymap
- 即编译器生成的定义将复制 this_
指针。移动构造函数的示例实现可以是
Y(Y&& y) : b(y.b), mymap(std::make_move_iterator(std::begin(y.mymap)),
std::make_move_iterator(std::end (y.mymap)), 0, {this}) {}
关于作为模板参数的 C++ 方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29632309/