C ++等于(==)重载,快捷方式或比较所有属性的最佳方式

时间:2016-02-29 16:27:50

标签: c++ operator-overloading

我必须在C ++中为具有许多属性的类重载==运算符 当且仅当所有属性相等时,运算符才应返回true。如果这些属性随时间变化,则快捷方式可能很有用,以避免错误。

是否有比较类中每个属性的快捷方式?

5 个答案:

答案 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