考虑下面的C ++代码:
class Foo {
public:
int a;
};
class Bar {
public:
int w = 1;
bool are_foos_equal(Foo* f1, Foo* f2) { return f1->a * w == f2->a * w; }
struct FooHash { size_t operator () (Foo* f) const { return f->a; } };
struct FooEqual {
bool operator () (Foo* f1, Foo* f2) const {
return are_foos_equal(f1, f2);
}
};
std::unordered_set<Foo*, FooHash, FooEqual> fooset;
};
现在,这不会编译,因为在operator ()
的{{1}}我无法调用非静态FooEqual
。
我的问题是:are_foos_equal
是否有可能以某种方式使用fooset
?我知道我可以让are_foos_equal
静态但我给出的示例代码只是为了说明我的问题,不幸的是,这个问题发生在一个更大的项目中,即使这意味着设计有些错误如果可能的话,我想用一些黑客来拯救它。
修改
我向are_foos_equal
添加了一个非静态成员变量w
,以强调Bar
的“非静态”。
答案 0 :(得分:3)
将are_foos_equal()
移到课堂外,使其成为免费功能。它应该是Bar
的成员是没有意义的。例如:
class Foo {
public:
int a;
};
bool are_foos_equal(Foo* f1, Foo* f2)
{return f1->a == f2->a;}
class Bar {
public:
struct FooHash { size_t operator () (Foo* f) const { return f->a; } };
struct FooEqual {
bool operator () (Foo* f1, Foo* f2) const {
return are_foos_equal(f1, f2);
}
};
std::unordered_set<Foo*, FooHash, FooEqual> fooset;
};
答案 1 :(得分:2)
正确的选择肯定是使are_foos_equal
静态。我强烈建议这样做而不是黑客攻击。项目越大,它就越需要清洁,以免它变成一个无法维护的混乱。
但如果这不是一个选项,我会看到其他一些可能性:
在Bar
内动态创建FooEqual
对象:
return Bar().are_foos_equal(f1, f2);
为此目的FooEqual
存储一个静态Bar
对象:
bool operator() (Foo* f1, Foo* f2) const {
static Bar bar;
return bar.are_foos_equal(f1, f2);
}
调用未定义的行为,在空指针上调用are_foos_equal
并希望它不会做任何坏事。我强烈反对这个:
return static_cast<Bar*>(nullptr)->are_foos_equal(f1, f2);
答案 2 :(得分:2)
您可以在Bar
中维护对父FooEqual
对象的引用:
Bar() : fooset{10, FooHash{}, FooEqual{*this}}
{}
struct FooEqual {
Bar& parent;
bool operator () (Foo* f1, Foo* f2) const {
return parent.are_foos_equal(f1, f2);
}
};
由于在std::unordered_set
中如何声明构造函数,您需要提供一个桶计数,这有点不幸。如果您愿意,可以从默认构造的std::unordered_set
获取默认值。
答案 3 :(得分:1)
这里可能很简单,因为are_foos_equal
可能是静态的,因为它既不会改变this
中的任何内容
=&GT;第一种方法只是声明are_foos_equal
静态。
或者,如果被调用的函数不能是静态的,因为它使用或更改了它的对象,则必须更改FooEqual
以包含Bar
对象(或指向它的指针或引用)。因为C ++不是java:内部类没有隐藏指向封闭类的对象的指针。
=&GT;第二种方法是在Bar
中添加对FooEqual
的引用,并在构建时设置它:
struct FooEqual {
const Bar &bar;
FooEqual(const Bar& bar): bar(bar) {};
bool operator () (Foo* f1, Foo* f2) const {
return bar.are_foos_equal(f1, f2);
}