我非常支持让编译器为你做尽可能多的工作。当编写一个简单的类时,编译器可以为你提供以下“免费”:

默认(空)构造函数 复制构造函数 一个析构函数 赋值运算符(operator=)

但是它似乎不能给你任何比较操作符——比如operator==或operator!=。例如:

class foo
{
public:
    std::string str_;
    int n_;
};

foo f1;        // Works
foo f2(f1);    // Works
foo f3;
f3 = f2;       // Works

if (f3 == f2)  // Fails
{ }

if (f3 != f2)  // Fails
{ }

这有什么好的理由吗?为什么执行逐个成员的比较是一个问题?显然,如果类分配内存,那么你要小心,但对于一个简单的类,编译器肯定可以为你做这个?


当前回答

编译器不会知道你想要的是指针比较还是深层(内部)比较。

更安全的做法是不实现它,让程序员自己来做。然后他们可以做出所有他们喜欢的假设。

其他回答

在这个视频中,STL的创造者Alex Stepanov在13:00左右回答了这个问题。总结一下,在见证了c++的发展之后,他认为:

It's unfortunate that == and != are not implicitly declared (and Bjarne agrees with him). A correct language should have those things ready for you (he goes further on to suggest you should not be able to define a != that breaks the semantics of ==) The reason this is the case has its roots (as many of C++ problems) in C. There, the assignment operator is implicitly defined with bit by bit assignment but that wouldn't work for ==. A more detailed explanation can be found in this article from Bjarne Stroustrup. In the follow up question Why then wasn't a member by member comparison used he says an amazing thing : C was kind of a homegrown language and the guy implementing these stuff for Ritchie told him he found this to be hard to implement!

然后他说,在(遥远的)未来,==和!=将隐式生成。

我同意,对于POD类型的类,编译器可以为你做。然而,你可能认为简单的编译器可能会出错。所以最好还是让程序员来做。

我曾经有一个POD案例,其中两个字段是唯一的-所以比较永远不会被认为是正确的。然而,我所需要的比较只是在有效负载上进行比较——这是编译器永远无法理解或自己无法解决的问题。

此外,他们不需要花很长时间来写,不是吗?!

这样,随着时间的推移,这个问题的答案仍然是完整的:从c++ 20开始,它可以通过命令auto操作符自动生成<=>(const foo&) const = default;

它将生成所有的运算符:==,!=,<,<=,>和>=,详细信息请参见https://en.cppreference.com/w/cpp/language/default_comparisons。

由于操作员的外观<=>,它被称为宇宙飞船操作员。另见为什么在c++中我们需要太空船<=>操作符?

EDIT:同样在c++ 11中,std::tie也提供了一个相当简洁的替代品,有关bool操作符<(…)的完整代码示例,请参阅https://en.cppreference.com/w/cpp/utility/tuple/tie。有趣的部分,改变为使用==是:

#include <tuple>

struct S {
………
bool operator==(const S& rhs) const
    {
        // compares n to rhs.n,
        // then s to rhs.s,
        // then d to rhs.d
        return std::tie(n, s, d) == std::tie(rhs.n, rhs.s, rhs.d);
    }
};

tie适用于所有比较操作符,并被编译器完全优化。

编译器不会知道你想要的是指针比较还是深层(内部)比较。

更安全的做法是不实现它,让程序员自己来做。然后他们可以做出所有他们喜欢的假设。

从概念上讲,定义平等并不容易。即使对于POD数据,有人可能会说,即使字段是相同的,但它是不同的对象(在不同的地址),它也不一定相等。这实际上取决于操作符的用法。不幸的是,你的编译器不是通灵的,不能推断。

除此之外,默认函数是搬起石头砸自己的脚的好方法。你描述的默认值基本上是为了保持与POD结构体的兼容性。然而,它们确实会造成足够多的破坏,让开发人员忘记它们或默认实现的语义。