我必须在C ++中为具有许多属性的类重载==运算符 当且仅当所有属性相等时,运算符才应返回true。如果这些属性随时间变化,则快捷方式可能很有用,以避免错误。
是否有比较类中每个属性的快捷方式?
答案 0 :(得分:40)
没有捷径。你必须列出一切。
通过引入名为tied()
的成员函数,可以减少一些错误来源:
struct Foo {
A a;
B b;
C c;
...
private:
auto tied() const { return std::tie(a, b, c, ...); }
};
这样您的operator==
就可以使用它:
bool operator==(Foo const& rhs) const { return tied() == rhs.tied(); }
这使您只能列出一次所有成员。但那是关于它的。你仍然需要实际列出它们(所以你仍然可以忘记一个)。
有一个提案(P0221R0)来创建默认operator==
,但我不知道它是否会被接受。
答案 1 :(得分:16)
从C ++ 11开始,引入tuples我们也得到了std::tie()
。这将允许使用从一堆变量中创建一个元组,并针对所有变量调用一个比较函数。您可以像
struct Foo
{
int a,b,c,d,e,f;
bool operator==(const Foo& rhs) { return std::tie(a,b,c,d,e,f) == std::tie(rhs.a,rhs.b,rhs.c,rhs.d,rhs.e,rhs.f); }
};
您仍然需要列出要检查的所有成员,但这样会更容易。您也可以使用它来更轻松地进行比较而不是比较。
还应注意,变量按照您提供给tie
的顺序进行检查。这对于小于和大于比较而言非常重要。
std::tie(a,b) < std::tie(rhs.a, rhs.b);
不必与
相同std::tie(b,a) < std::tie(rhs.b, rhs.a);
答案 2 :(得分:5)
目前,没有捷径,但有计划增加对它的支持(P0221R0)。
Bjarne Stroustrup最近写了一篇关于它的博客文章: A bit of background for the default comparison proposal
在C ++ 14中,没有比列出所有成员和比较它们更好的了,这很容易出错。引用Bjarne:
默认比较的杀手论证实际上并不方便,而是人们弄错了等式算子。
答案 3 :(得分:2)
不幸的是,检查所有属性是唯一的方法。好的是,如果您使用&&
组合所有检查,它将在第一个错误陈述后停止评估。 (短路评估)
所以,例如false && (4 == 4)
。该程序永远不会评估4 == 4
部分,因为&&
合并的所有语句都需要true
才能获得true
作为最终结果。这有意义吗?
答案 4 :(得分:1)
不存在operator==
相关解决方案。您可以在所谓的X-Macro的帮助下从定义表中生成相关代码。该表可能看起来像
#define MEMBER_TBL \
/*type ,name ,default*/ \
X(int ,_(i) ,42 ) \
X(float ,_(f) ,3.14 ) \
X(std::string , t ,"Hello") \
需要使用_()
内容来避免在生成,
电话时追踪std::tie()
。确保最后一个元素是w.o. _()
。生成成员的用法是:
struct Foo
{
#define _(x) x
#define X(type, name, default) type name{default};
MEMBER_TBL
#undef X
#undef _
}
这会产生:
struct Foo
{
int i{42}; float f{3.14}; std::string t{"Hello"};
}
要生成operator==
,您可以使用:
bool operator==(Foo const& other) const {
return std::tie(
#define _(x) x,
#define X(type, name, default) this->name
MEMBER_TBL
#undef X
) == std::tie(
#define X(type, name, default) other.name
MEMBER_TBL
#undef X
#undef _
);
}
导致
bool operator==(Foo const& other) const {
return std::tie(
this->i, this->f, this->t
) == std::tie(
other.i, other.f, other.t
);
}
要添加新成员,您只需向第一个表添加一个新条目即可。其他一切都是自动生成的。
另一个优点是,您只需添加dump()
方法,例如
void print(void) const {
#define STR(x) #x
#define _(x) x
#define X(type, name, default) \
std::cout << \
STR(name) << ": " << name << " ";
MEMBER_TBL
#undef X
#undef _
#undef STR
std::cout << std::endl;
}
导致
void print() const {
std::cout << "i" << ": " << i << " "; std::cout << "f" << ": " << f << " "; std::cout << "t" << ": " << t << " ";
std::cout << std::endl;
}
有关会员的每一条信息都可以在一个地方(单点信息)添加到表格中,并在其他地方提取。
工作Demo。