没有为C ++ 20中的自定义太空船运算符实现定义等式运算符

Zee*_*bit 42 c++ spaceship-operator c++20

<=>在C ++ 20中使用新的宇宙飞船运算符遇到一种奇怪的行为。我正在将Visual Studio 2019编译器与一起使用/std:c++latest

这段代码可以正常编译:

#include <compare>

struct X
{
    int Dummy = 0;
    auto operator<=>(const X&) const = default; // Default implementation
};

int main()
{
    X a, b;

    a == b; // OK!

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

但是,如果我将X更改为:

struct X
{
    int Dummy = 0;
    auto operator<=>(const X& other) const
    {
        return Dummy <=> other.Dummy;
    }
};
Run Code Online (Sandbox Code Playgroud)

我收到以下编译器错误:

error C2676: binary '==': 'X' does not define this operator or a conversion to a type acceptable to the predefined operator

我也在clang上尝试了这一点,并且得到了类似的行为。

我希望对为什么默认实现operator==能够正确生成但自定义实现不能正确生成的一些解释进行说明。

Sto*_*ica 47

这是设计使然。

[class.compare.default](强调我的)

3如果类定义没有显式声明== 运算符,而是声明了默认的三向比较运算符==则隐式声明一个运算符,其访问方式与三向比较运算符相同。==类X 的隐式声明的运算符是内联成员,并且在X的定义中定义为默认值。

只有默认值<=>允许合成==存在。理由是像这样的类std::vector不能使用defaulted <=>。另外,使用<=>for ==并不是比较向量的最有效方法。<=>必须给出确切的顺序,而==可能会通过先比较尺寸来提前保释。

如果一个类在其三向比较中做一些特殊的事情,则可能需要在其中做一些特殊的事情==。因此,该语言不会产生不合理的默认值,而是将其留给程序员。

  • @Deduplicator - 敏感性是主观的。有些人会说默默生成的低效实现是不明智的。 (3认同)
  • 除非飞船是越野车,否则这当然是明智的。潜在的严重低效率... (2认同)

Nic*_*las 39

在此功能的标准化期间,决定逻辑上应将相等性和顺序分开。因此,对等式测试(==!=)的使用永远不会调用operator<=>。但是,仍然可以使用单个声明将它们都默认为默认值。因此,如果您使用default operator<=>,则决定还打算使用default operator==(除非您稍后定义它或早先定义它)。

至于为什么做出这个决定,基本的推理是这样的。考虑一下std::string。两个字符串的顺序是按字典顺序排列的;每个字符都有其整数值,与另一个字符串中的每个字符相比。第一个不等式导致排序的结果。

但是,字符串的相等性测试存在短路。如果两个字符串的长度不相等,那么完全没有必要进行字符比较;他们是不平等的。因此,如果有人正在进行相等性测试,那么如果您可以使它短路,那么您就不希望这样做。

事实证明,许多需要用户定义排序的类型也将提供用于相等性测试的某种短路机制。为了防止人们仅执行operator<=>并丢弃潜在的性能,我们有效地迫使每个人都做到。

  • 这是一个比公认答案更好的解释 (4认同)

Okt*_*ist 14

The other answers explain really well why the language is like this. I just wanted to add that in case it's not obvious, it is of course possible to have a user-provided operator<=> with a defaulted operator==. You just need to explicitly write the defaulted operator==:

struct X
{
    int Dummy = 0;
    auto operator<=>(const X& other) const
    {
        return Dummy <=> other.Dummy;
    }
    bool operator==(const X& other) const = default;
};
Run Code Online (Sandbox Code Playgroud)

  • 也许请注意,默认的“operator==”不使用“operator&lt;=&gt;”。 (5认同)