等値演算子は、C ++ 20のカスタム宇宙船演算子の実装に対して定義されていません


51

<=>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;
}

ただし、Xを次のように変更すると、

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

次のコンパイラエラーが発生します。

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

これをclangでも試しましたが、同様の動作が得られます。

デフォルトの実装がoperator==正しく生成される理由について説明をいただければ幸いですが、カスタムの実装では生成されません。

回答:


50

これは仕様によるものです。

[class.compare.default](強調鉱山)

3クラス定義で== 演算子関数が明示的に宣言されておらず、デフォルトの3者間比較演算==子関数が宣言されている場合、演算子関数は3者間比較演算子関数と同じアクセス権で暗黙的に宣言されます。==クラスX の暗黙的に宣言された演算子はインラインメンバーであり、Xの定義でデフォルトとして定義されています。

デフォルトのみが<=>合成の==存在を許可します。その理由は、などのクラスstd::vectorはデフォルトを使用できないということ<=>です。また、<=>for を使用すること==は、ベクトルを比較する最も効率的な方法ではありません。<=>正確な順序を与える必要がありますが、==サイズを最初に比較することで早期に保釈される可能性があります。

クラスが3者間比較で特別なことを行う場合、そのクラスで特別なことを行う必要があります==。したがって、意味のないデフォルトを生成する代わりに、言語はそれをプログラマーに任せます。


4
宇宙船がバギーでない限り、それは確かに賢明です。ただし、非常に非効率的な可能性があります...
重複排除

1
@Deduplicator-感度は主観的です。静かに生成された非効率的な実装は賢明ではないと言う人もいます。
StoryTeller-Unslander Monica

45

この機能の標準化中に、等価性と順序付けを論理的に分離する必要があることが決定されました。したがって、等価テスト(==および!=)を使用しても、は呼び出されませんoperator<=>。ただし、1つの宣言で両方のデフォルトを設定できると便利であると見なされていました。したがって、defaultの場合operator<=>operator==(後で定義したり、以前に定義した場合を除いて)defaultにすることも決定されました。

この決定が行われた理由、基本的な推論はこのように書きます。考えてくださいstd::string。2つの文字列の順序は辞書式です。各文字には、他の文字列の各文字と比較した整数値があります。最初の不等式は、順序付けの結果になります。

ただし、文字列の等価性テストには短絡があります。2つの文字列の長さが等しくない場合は、文字単位で比較してもまったく意味がありません。それらは等しくありません。したがって、誰かが同等性テストを行っている場合、短絡させることができるのであれば、長時間テストする必要はありません。

ユーザー定義の順序付けを必要とする多くのタイプは、同等性テスト用の短絡メカニズムも提供することがわかります。人々がoperator<=>潜在的なパフォーマンスのみを実装して捨てることを防ぐために、私たちは効果的にすべての人に両方を行うことを強制します。


5
これが受け入れ答えよりもはるかに優れている説明
メモ

17

他の答えは、言語がこのようなものである理由を本当によく説明しています。それが明白でない場合に備えて、それを追加したかっただけです。もちろんoperator<=>、デフォルトのをユーザーに提供することは可能operator==です。デフォルトを明示的に書くだけですoperator==

struct X
{
    int Dummy = 0;
    auto operator<=>(const X& other) const
    {
        return Dummy <=> other.Dummy;
    }
    bool operator==(const X& other) const = default;
};
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.