最終更新日時: 2026年07月22日 16時38分23秒 (JST)
rotarymars が更新

履歴 編集

customization point object
<compare>

# std::weak_order(C++20)

    namespace std {
      inline namespace /*unspecified*/ {

        inline constexpr /*unspecified*/ weak_order = /*unspecified*/;
      }
    }

## 概要

`weak_order`は2つの引数を受け取り、それらを弱順序の上で比較する関数オブジェクトである。

## 効果

`weak_order(a, b)`のように呼び出された時、以下のいずれかと等価（上から順に考慮される）

1. `decay`を通した`a, b`の型が異なる場合、呼び出しは不適格（コンパイルエラー）

2. `weak_order(a, b)`の`weak_order`の意味がADLのみによって決まるコンテキストで、`weak_ordering(weak_order(a, b))`が呼び出し可能ならば`weak_ordering(weak_order(a, b))`

3. `decay`を通した`a, b`の型`T`が浮動小数点型の場合、`T`の組み込みの比較演算子および`strong_order`による順序と一貫する`weak_ordering`の値を返す。
   さらに、`numeric_limits<T>::is_iec559 == true`の場合、追加で以下の同値類の順序に従った順序付けを行う。

   1. 全ての`-NaN`
   2. `-Inf`
   3. 負の正規化数
   4. 負の非正規化数
   5. `±0.0`
   6. 正の非正規化数
   7. 正の正規化数
   8. `+Inf`
   9. 全ての`+NaN`

4. `weak_ordering(a <=> b)`が呼び出し可能ならば`weak_ordering(a <=> b)`

5. `weak_ordering(strong_order(a, b))`が呼び出し可能ならば`weak_ordering(strong_order(a, b))`

6. それ以外の場合、呼び出しは不適格。

## 戻り値

呼び出しが適格ならば、比較結果を表す`weak_ordering`の値。

## 例外

上記「効果」節のそれぞれのケース毎に

1. --
2. 呼び出される`weak_order(a, b)`およびその戻り値の`weak_ordering`への変換が例外を送出するかに従う。
3. 投げない。
4. 呼び出される`a <=> b`およびその戻り値の`weak_ordering`への変換が例外を送出するかに従う。
5. 呼び出される`strong_order(a, b)`およびその戻り値の`weak_ordering`への変換が例外を送出するかに従う。

## 定数式に評価される条件

上記「効果」節のそれぞれのケース毎に

1. --
2. 呼び出される`weak_order(a, b)`およびその戻り値の`weak_ordering`への変換が定数評価可能であるかに従う。
3. 常に定数評価可能
4. 呼び出される`a <=> b`およびその戻り値の`weak_ordering`への変換が定数評価可能であるかに従う。
5. 呼び出される`strong_order(a, b)`およびその戻り値の`weak_ordering`への変換が定数評価可能であるかに従う。

## カスタマイゼーションポイント

上記「効果」節2,4,5のケースでは、ユーザー定義の`weak_order()`、`<=>`演算子を定義、もしくは`strong_order()`へアダプトしておくことによって実行される比較をカスタマイズすることができる。

1. --
2. 引数`a, b`の型`T`と同じ名前空間、もしくは`T`の定義内で`friend`関数として`weak_order()`を定義しておく。
3. --
4. 引数`a, b`の型`T`に対して、使用可能な`<=>`演算子を定義しておく。
5. 引数`a, b`の型`T`を`strong_order`にアダプトしておく。

ただし、どのケースにおいてもその戻り値型は`weak_ordering`に変換可能でなければならない。

## 備考

`numeric_limits<T>::is_iec559 == true`の場合の浮動小数点数の比較において、各同値類間の順序は以下のようになる。

{全ての`-NaN`} `<` {`-Inf`} `<` {負の正規化数} `<` {負の非正規化数} `<` {`±0.0`} `<` {正の非正規化数} `<` {正の正規化数} `<` {`+Inf`} `<` {全ての`+NaN`}

それぞれの同値類における順序付けは通常の比較演算子の順序付けに従う。ただし、比較不能である場合はその値は同値として扱われる。すなわち、{`±0.0`}および{`±NaN`}のそれぞの同値類では全ての値が同値(`=`)として扱われる。

## 例

    #include <iostream>
    #include <compare>
    #include <limits>

    struct no_spaceship {
      int n1 = 0;
      int n2 = 0;
      int n3 = 0;

      friend auto weak_order(const no_spaceship& lhs, const no_spaceship& rhs) -> std::weak_ordering {
        //1 -> 3 -> 2の順で比較
        if (auto cmp = lhs.n1 <=> rhs.n1; cmp != 0) return cmp;
        if (auto cmp = lhs.n3 <=> rhs.n3; cmp != 0) return cmp;
        return lhs.n2 <=> rhs.n2;
      }
    };

    struct have_spaceship {
      int n1 = 0;
      int n2 = 0;
      int n3 = 0;

      friend auto operator<=>(const have_spaceship& lhs, const have_spaceship& rhs) -> std::weak_ordering {
        //宣言と逆順で比較
        if (auto cmp = lhs.n3 <=> rhs.n3; cmp != 0) return cmp;
        if (auto cmp = lhs.n2 <=> rhs.n2; cmp != 0) return cmp;
        return lhs.n1 <=> rhs.n1;
      }

      friend auto operator==(const have_spaceship& lhs, const have_spaceship& rhs) -> bool = default;
    };

    int main()
    {
      std::cout << std::boolalpha;

      //2. ユーザー定義weak_order()によるカスタム比較
      no_spaceship s1 = {1, 2, 3}, s2 = {2, 1, 3};
      std::cout << (std::weak_order(s1, s2) < 0) << std::endl;

      std::cout << "\n";

      //3. 浮動小数点数の比較
      constexpr auto qnan = std::numeric_limits<double>::quiet_NaN();
      constexpr auto snan = std::numeric_limits<double>::signaling_NaN();

      std::cout << (std::weak_order(-0.0, +0.0) == 0) << std::endl;
      std::cout << (std::weak_order(-qnan, +qnan) < 0) << std::endl;
      std::cout << (std::weak_order(qnan, snan) == 0) << std::endl;

      std::cout << "\n";

      //4. ユーザー定義<=>によるカスタム比較
      have_spaceship s3 = {1, 2, 3}, s4 = {2, 1, 3};
      std::cout << (std::weak_order(s3, s4) < 0) << std::endl;

      std::cout << "\n";

      //4. 組み込み型の比較
      std::cout << (std::weak_order(1, 2) < 0) << std::endl;
    }

### 出力

    true

    true
    true
    true

    false

    true

## バージョン

### 言語

- C++20

### 処理系

- Clang: ??
- GCC: 10.1 ✅
- Visual C++: ??

## 関連項目

- C++20 `<=>`/`==`による比較演算子の自動定義
- `strong_order`
- `weak_ordering`
- `compare_weak_order_fallback`

## 参照

- P0768R1 Library support for the spaceship (comparison) operator
- P1614R2 The Mothership has Landed (Adding <=> to the Library)
- P2602R2 Poison Pills are Too Toxic