宇宙船オペレーターを修正するための提案

私は最近、比較に関するシリーズを作成し、3 者間の比較のために今後の宇宙船オペレーターを使用するためのガイドラインをいくつか提供しました.特に、現在の設計のいくつかの欠陥を指摘しました.

さて、次の C++ 標準化会議の提案がここにあります — ほぼ 300 件あります。数えてみると、そのうち 11 件は宇宙船のオペレーターを扱っています。

それでは、それらを見て、私が指摘した問題のいずれかが修正されるかどうかを見てみましょう。

05 の使用によるパフォーマンスへの影響 平等のために

素晴らしい名前の P1190 — 「私はこれを注文していません!」 — 18 を使用した場合の影響について詳しく説明します 平等が必要な場合は、最後の部分で簡単に説明しましたが、基本的な問題は次のとおりです。

template <typename T>
auto operator<=>(const std::vector<T>& lhs, const std::vector<T>& rhs)
{
    auto lhs_cur = lhs.begin();
    auto lhs_end = lhs.end();
    auto rhs_cur = rhs.begin();
    auto rhs_end = rhs.end();

    for (; lhs_cur != lhs_end && rhs_cur != rhs_end; ++lhs_cur, ++rhs_cur)
    {       
        // compare each member
        auto cmp = *lhs_cur <=> *rhs_cur;
        if (cmp != 0)
            // they aren't equal, so return that as the result
            return cmp;
        // otherwise continue
    }

    // at this point all members in the common prefix are equal
    if (lhs_cur != lhs_end)
        // lhs is bigger, so it's greater
        return std::strong_ordering::greater;
    else if (rhs_cur != rhs_end)
        // lhs is smaller, so it's less
        return std::strong_ordering::less;
    else
        // both are completely equal
        return std::strong_ordering::equal.
}

上記は、27 の宇宙船オペレーターの可能な実装です。 :これは、std::lexicographical_compare_3way が行うように、単純に辞書式の 3 者間比較を行います。

その定義を使用すると、 35 を実行できます コンパイラはそれを 48 に書き換えます .

しかし、 59 もできます コンパイラはそれを 66 に書き換えます .これは理想的ではありません!

コンテナが等しいかどうかだけを比較したい場合は、最初にサイズを確認します 、最後ではありません:2 つのコンテナーのサイズが異なる場合、それらを等しくすることはできないため、ループは必要ありません。

これは 76 と書くことを意味します コンテナの場合、84 も必要です。 パフォーマンス上の理由から。そして 91 として 106 まで延期します 、 111 も必要です .したがって、1 つだけでなく 3 つのオペレーターが必要です — これは良いことですが、それでも理想的ではありません。

提案はいくつかの解決策を指摘していますが、明示的に提案していません.

パフォーマンスへの影響の修正

ここで P1185 の出番です。これは、次の 3 つの部分からなる問題に対する適切な解決策を提案します。

<オール> <リ>

123 のルックアップを変更 と 136 : 142 156 のみを検索します 163 ではなくオーバーロード .しかし、それでも対称的に行われるので、必要なのは 174 だけです 、型を逆にした追加バージョンではありません。同様に、189 196 を試します または 206 215 ではありません .これにより、 228 を書くことができます と 238 効率を最大限に高めます。

<リ>

242 を生成 256 生成時 : ただし、上記の修正には残念な結果があります。 、あなたは平等ではなく、順序付けのみを取得します。したがって、論文には、デフォルトの宇宙船オペレーターもデフォルトの272を生成するというオプションの提案があります 、再び 1 つのデフォルト宣言で完全な順序付けと等価性を実現します。

<リ>

デフォルトの比較演算子の実装を修正: デフォルトの 281 294 にディスパッチされただけでは役に立ちません もう一度!デフォルトの 304 317 を使用してすべてのメンバーの辞書式比較を行います 、デフォルトの 321 すべてのメンバーを 331 と比較します 343 で連鎖された結果を返します .そうすれば、より効率的な 355 を実際に拾うことができます。 コンテナの種類の数!

この提案では、コンテナー タイプの作成者は次の 2 つのことを行う必要があります。

<オール>
  • 辞書式 364 を書く .
  • 最適化された 370 を書く .
  • その後、すべての比較演算子が機能し、可能な限り高速になります。

    そして、単純なクラスの作成者は、以前のように宇宙船演算子をデフォルトにするだけで、より高速な等値演算子を自動的に取得できます!

    383 の一般的なスペル 396 じゃないですか

    400 を見てください 414 の実装 再び上で与えられた:423 を呼び出して、各メンバーの辞書式比較を行います。 .

    前に言ったように、それは間違っています。

    431 の場合 型に 447 がない場合はコンパイルされません ただし、459 のみ と 469 .そして今のところ、478 を持つ型はありません !

    したがって、一般的なコードでは 489 を使用できません 直接、それを試して 497 を使用するようにフォールバックする必要があります および 505 3 者間比較用。少なくとも 517 はあります

    しかし、522 の一般的なスペルが間違っているのは本当に残念です。 535 です .

    P1186 は 545 に同意し、提案します 558 へのフォールバックを自動的に行う必要があります と 569 .そうすれば、常に 579 を使用できます

    そのときの名前は 587 再び利用可能になった場合、代わりに関数オブジェクトになることを提案しています:Where 592 605 を実行します 比較、614 621 を実行します 比較。

    比較シリーズの第 5 部でも同様に実装し、637 と呼びました。 .

    デフォルトの順序

    ただし、P0891 は別の名前に似た名前を付けたいと考えています。

    648 のように正しい順序を提供できない型があります。 .652 があるというだけでは意味がありません 順序付けが数学的特性と互換性がないためです。

    それでも、667 を使用するのはまったく合理的です。 マップのキーとして。そのためにはいくつか必要です 賢明ではありません。

    同様に 678 を使用 マップ内のキーにより、より効率的な順序付けも可能になるため、最初に長さで並べ替え、次に各要素を並べ替えます。長さの異なるコンテナがたくさんある限り、比較は依然として高速です。結果の順序付けはあまり役に立ちません。 、しかしそうである必要はありません — 有効なものである必要があります.

    だから 681 実際には 693 を使用しないでください (または 707 ) 直接、別のカスタマイズ ポイントを使用する必要があります。

    これが論文の提案です。新しいカスタマイズ ポイントは 719 と呼ばれます。 型のデフォルトの順序を返します。727 を持たない型に提供できます。 とにかくコンテナ内でそれらを使用することを許可します.

    比較シリーズのパート 5 では、734 と呼びました。 .

    以前の提案が両方とも受け入れられた場合、それは次のことを意味します:

      <リ>

      ジェネリックコードで何かが等しいかどうかをチェックしたい場合は、 749 を使用してください .それはできるだけ速くなり、三者間比較に書き直されません.

      <リ>

      3 者間比較を行う場合は、754 を使用します 763 に手動でフォールバックする必要はありません。 または 779 .

      <リ>

      3 者間比較を関数オブジェクトとして行う必要がある場合は、785 を使用します。 .それはちょうど 799 のようなものです 806 の場合 または 817 822 の場合 .

      <リ>

      いくつかが必要な場合 タイプの順序付けには、837 を使用します .並べ替えと二分探索だけが必要な場合は、任意の順序付けを実装します。

    標準ライブラリ型には 849 がありません

    宇宙船の提案では 858 が追加されましたが、 861 のような組み込み型に 、それらを標準ライブラリに追加しませんでした。現在のセマンティクスは 871 です 3者間比較で使用できないため、これは悪いことです!

    したがって、P0790 は 885 の追加を提案しています 現在 899 を持つすべての型へのオーバーロード または 904 .

    自動フォールバックが受け入れられる場合、この追加は必要ないかもしれません。

    ただし、まだ必要なのは P1191 です。これは、現在まったく比較を行わない 2 つの型に 3 者間比較 (したがって通常の比較) を追加することを提案しています。正確には、型の等価性のみを提案しています。 913 のように または非常に重要でよく使用される 922 .

    その他のライブラリの改善

    P1310 を引用すると、2 つの文字列を比較する場合は、次のようになります。

    • 934 (947 を返します )
    • 950 (964 を返します )
    • 972 (984 を返します )
    • 998 (1007 を返します )
    • 1013 (1023 を返します )
    • 1030 (1043 を返します )
    • 1054 (1066 を返します )
    • 1074 (1080 を返します )
    • 1092 (1102 を返します )
    • 1112 (1123 を返します 、2 つのパスが同じファイルに解決されるかどうかの弱等号を提供します)

    これは、さまざまな戻り値の型とそうでないものがあるため、少し混乱しています。

    したがって、代わりに単一の統一 1137 が必要です 1148 を非推奨にすることに同意しないことに注意してください。 1150 に賛成 !詳細については、私の比較シリーズまたは P1307 をお読みください。

    現在の標準ライブラリには 1166 のような概念があります または 1178 1188 で機能する .P1312 は、1191 でも動作することを提案しています。 および 1202 1212 のような名前付き比較関数として弱い順序付けを実装するという私のガイドラインに従うことができるため、これは非常に重要な変更です。 .次に、それらを 1221 に渡すだけです または 1235 手動でラップする必要はありません!

    1248 のような概念の変更を提案していないことに注意してください。 1257 を使用するには 1264 として 1270 しかない型でも機能します .

    いくつかの順序付けアルゴリズムを実装したとき、trait 1281 を書きました P1187 は 1295 という名前で提案しています。 .

    そして最後に、P0863 は 1300 の潜在的なバグの修正について説明します .順序付けの背後にある数学の簡単な要約:半順序では、2 つの型は、小さい/大きい/等しいか、または順序付けされていない可能性があります。ただし、1311 1324 を返すことはありません !

    結論

    する これについて引用してください:

    P1186 1333 なし 汎用コードではまったく役に立ちません。そして、P1185 は高速に不可欠です。 ジェネリック コード。コンセプトにより、ジェネリック コードは初心者にとってより簡単で親しみやすいものになるはずです。これ以上の落とし穴は必要ありません。

    他の提案も有用ですが、これら 2 つは 1340 を本当に洗練するために重要です。 .C++20 に組み込まれることを心から願っています。