web-dev-qa-db-ja.com

3者間比較演算子は減算とどのように違いますか?

C++ 20には、新しい比較演算子<=>があります。しかし、ほとんどの場合、単純な減算はうまくいくと思います:

int my_strcmp(const char *a, const char *b) {
    while (*a == *b && *a != 0 && *b != 0) {
        a++, b++;
    }
    // Version 1
    return *a - *b;
    // Version 2
    return *a <=> *b;
    // Version 3
    return ((*a > *b) - (*a < *b));
}

それらは同じ効果があります。違いを本当に理解できません。

50
iBug

演算子は、減算で得られる数値オーバーフローの問題を解決します。INT_MINに近い負の値から大きな正の値を減算すると、intとして表現できない数が得られます。したがって、未定義の動作が発生します。

バージョン3にはこの問題はありませんが、読みやすさはまったくありません。このトリックを見たことがない人が理解するのに時間がかかるでしょう。 <=>演算子も読みやすさの問題を修正します。

これは、新しいオペレーターが対処する1つの問題にすぎません。 Herb Sutter'sConsistent comparisonpaper のセクション2.2.3は、他のデータ型の<=>の使用について説明しています。減算によって一貫性のない結果が生じる可能性のある言語。

52
dasblinkenlight

減算が機能しない場合の例を次に示します。

  1. unsignedタイプ。
  2. 整数オーバーフローを引き起こすオペランド。
  3. operator -を定義しないユーザー定義型(おそらく意味がないため-距離の概念を定義せずに順序を定義できます)。

このリストは網羅的ではないと思います。

もちろん、少なくとも1番目と2番目の回避策を考え出すことができます。しかし、operator <=>の目的は、そのさをカプセル化することです。

40

ここには違いについていくつかの有意義な答えがありますが、 彼の論文 のハーブサッターは具体的に次のように述べています。

<=>は型の実装者向けです。operator<=>の実装外のユーザーコード(汎用コードを含む)は、<=>を直接呼び出すことはほとんどありません(他の言語で既によく知られています)。

したがって、違いがなかったとしても、演算子のポイントは異なります。クラスライターが比較演算子を生成するのを支援するためです。

(Sutterの提案による)減算演算子と「宇宙船」演算子の主な違いは、operator-をオーバーロードすると減算演算子が得られるのに対して、operator<=>をオーバーロードすると言うことです。

  • 6つのコア比較演算子を提供します(演算子をdefaultとして宣言した場合でも:記述するコードはありません!);
  • クラスが比較可能かどうか、ソート可能かどうか、および順序が全体か部分か(Sutterの提案の強い/弱い)を宣言します。
  • 異種比較を可能にします:クラスを他の型と比較するためにそれをオーバーロードできます。

その他の違いは戻り値にあります:operator<=>はクラスのenumを返します。クラスは型がソート可能かどうか、およびソートが強いか弱いかを指定します。戻り値は-1、0、または1に変換されます(ただし、Sutterはstrcmpが行うように、戻り値のタイプも距離を示す余地を残しています)。いずれの場合も、-1、0、1の戻り値を想定して、最終的に C++の真のsignum関数 !を取得します。 (signum(x) == x<=>0

16
Cris Luengo