我正在尝试使用自定义哈希和自定义相等来为类X专门化std :: unordered_map。问题是,相等和散列函数不仅依赖于类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也是一个模板,以防万一。
谢谢!
编辑:为了澄清,我的代码中没有布尔值b,我有一个向量,其中包含了比较X类型对象所需的数据。一些数据是在创建X时添加的,因此向量不是常量,而是给定X的数据在添加后不会改变,因此给定X的散列永远不会改变(因此在某种意义上它只取决于散列所需的X)。我使用这种方法的主要原因是节省内存,因为这些数据很多并且通常是共享的。
答案 0 :(得分:2)
不幸的是,你想做的事情是不合法的。见17.6.3.5/Table 26:
h(k)
返回的值仅取决于参数k。
很明显,您不允许哈希取决于Y
以及X
的成员。
编辑:以防万一{/ 1}} b
成为你的Y
类中的const有一个解决方案(我还没有编译它,如果有机会的话我会的):< / p>
struct Y
{
explicit Y(bool config) : b(config), hash_(config), mymap(0, hash_) { }
const bool b;
struct X
{
size_t i;
};
struct Hash
{
explicit Hash(bool b) : b_(b) { }
size_t operator()(const X& x) const
{
return x.i + b_;
}
private:
bool b_;
};
Hash hash_;
unordered_map<X, int, Hash> mymap;
};
答案 1 :(得分:2)
您可以使用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}) {}