Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/152.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 非默认操作员<=&燃气轮机;不';t生成==和!=在C++;20_C++_C++20_Spaceship Operator - Fatal编程技术网

C++ 非默认操作员<=&燃气轮机;不';t生成==和!=在C++;20

C++ 非默认操作员<=&燃气轮机;不';t生成==和!=在C++;20,c++,c++20,spaceship-operator,C++,C++20,Spaceship Operator,我在C++20中遇到了一个新的宇宙飞船操作符的奇怪行为。我正在将Visual Studio 2019编译器与/std:c++最新版本一起使用 这段代码编译得很好,正如预期的那样: #include <compare> struct X { int Dummy = 0; auto operator<=>(const X&) const = default; // Default implementation }; int main() {

我在C++20中遇到了一个新的宇宙飞船操作符
的奇怪行为。我正在将Visual Studio 2019编译器与
/std:c++最新版本一起使用

这段代码编译得很好,正如预期的那样:

#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;
}
#包括
结构X
{
int-Dummy=0;
自动运算符(const X&)const=default;//默认实现
};
int main()
{
xa,b;
a==b;//好的!
返回0;
}
但是,如果我将X更改为:

struct X
{
    int Dummy = 0;
    auto operator<=>(const X& other) const
    {
        return Dummy <=> other.Dummy;
    }
};
struct X
{
int-Dummy=0;
自动操作员(常数X和其他)常数
{
返回虚拟其他。虚拟;
}
};
我发现以下编译器错误:

错误C2676:二进制“==”:“X”未定义此运算符或到预定义运算符可接受类型的转换

我也在叮当声上试过,我得到了类似的行为


我希望您能解释一下为什么默认实现会正确地生成
运算符==
,而自定义实现不会。

在该功能的标准化过程中,决定在逻辑上将相等和排序分开。同样地,使用相等测试(
=
!=
)将永远不会调用
操作符。然而,人们仍然认为,能够用一个声明来默认这两个选项是有用的。因此,如果您使用默认的
操作符
,则决定您也要使用默认的
操作符==
(除非您稍后定义它或之前定义过它)

至于,基本的推理是这样的。考虑<代码> STD::String < /代码>。两个字符串的顺序是按字典顺序排列的;每个字符都有其整数值,与另一个字符串中的每个字符进行比较。第一个不等式导致排序的结果

但是,字符串的相等性测试存在短路。如果两个字符串的长度不相等,那么进行字符级比较就毫无意义;他们不平等。所以,如果有人在做平等性测试,如果你能短路它,你就不想做冗长的测试

事实证明,许多需要用户定义顺序的类型也会为相等性测试提供一些短路机制。为了防止人们只实现
操作符
而丢弃潜在的性能,我们有效地迫使每个人都这样做。

这是出于设计

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

如果类定义没有显式声明
==
运算符函数,但声明了默认的三向比较 运算符函数,隐式声明
=
运算符函数 具有与三向比较运算符功能相同的访问权限。 类X的隐式声明的
=
运算符是内联运算符 成员,并在X的定义中定义为默认值

只有默认的
允许存在合成的
=
。基本原理是像
std::vector
这样的类不应该使用非默认的
进行相等性测试。对
=
使用
并不是比较向量的最有效方法<代码>
必须给出准确的顺序,而
=
可以通过先比较大小来提前退出


如果一个类在它的三向比较中做了一些特殊的事情,那么它可能需要在它的
==
中做一些特殊的事情。因此,该语言没有生成一个潜在的不合理的默认值,而是将其留给程序员来处理。

其他答案很好地解释了为什么该语言是这样的。我只是想补充一点,如果不明显,当然可以让用户使用默认的
操作符==
提供
操作符。只需显式编写默认的
运算符==

struct X
{
    int Dummy = 0;
    auto operator<=>(const X& other) const
    {
        return Dummy <=> other.Dummy;
    }
    bool operator==(const X& other) const = default;
};
struct X
{
int-Dummy=0;
自动操作员(常数X和其他)常数
{
返回虚拟其他。虚拟;
}
布尔运算符==(常量X和其他)常量=默认值;
};

这当然是明智的,除非宇宙飞船有四轮马车。但可能效率极低…@重复数据消除-敏感性是主观的。有人会说,一个无声生成的低效实现是不明智的。这个标题使得谷歌搜索时更难找到这个问题。也许应该改为
非默认运算符不生成==和=。我碰巧遇到了后面的人,我打算问一个类似的问题,然后自己回答。