c++方法作为模板参数

c++ method as template argument

本文关键字:参数 方法 c++      更新时间:2023-10-16

我正试图用自定义哈希和自定义等式来专门化类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)。我使用这种方法的主要原因是为了节省内存,因为这些数据很多,而且通常是共享的。

您可以使用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}) {}

不幸的是,您想要做的是不合法的。见17.6.3.5表26:

h(k)返回的值应仅取决于参数k。

很明显,不允许哈希依赖于YX的成员。

编辑:如果你想让b在你的Y类中成为常量,有一个解决方案(我还没有编译这个,如果有机会的话我会编译的):

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