最終更新日時(UTC):
が更新

履歴 編集

customization point object
<compare>

std::strong_order(C++20)

namespace std {
  inline namespace /*unspecified*/ {

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

概要

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

効果

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

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

  2. std::strong_order(本関数オブジェクト)の宣言を含まないコンテキストで、strong_ordering(strong_order(a, b))が呼び出し可能ならばstrong_ordering(strong_order(a, b))

  3. decayを通したa, bの型Tが浮動小数点型の場合、Tの組み込みの比較演算子による順序と一貫するstrong_orderingの値を返す。
    さらに、numeric_limits<T>::is_iec559== trueの場合、その順序はISO/IEC/IEEE 60559のtotalOrderによる全順序と一致する。

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

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

戻り値

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

例外

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

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

定数式に評価される条件

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

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

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

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

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

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

備考

ISO/IEC/IEEE 60559のtotalOrderによる全順序では、±0や内部表現の異なるNaNを区別した上で順序付けされる。すなわち、本関数オブジェクトによる浮動小数点数の比較においてはこれらの値を識別することができる。

その順序付けは以下のようになる。

{負のquiet NaN} < {負のsignaling NaN} < {負の数} < -0.0 < +0.0 < {正の数} < {正のsignaling NaN} < {正のquiet NaN}

それぞれの種類のNaNの集合内では、NaNのペイロード(先頭ビットを除いた仮数部)の表現によって順序付けされる。

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

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

  friend auto strong_order(const no_spaceship& lhs, const no_spaceship& rhs) -> std::strong_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::strong_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;
  }
};


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

  //2. ユーザー定義strong_order()によるカスタム比較
  no_spaceship s1 = {1, 2, 3}, s2 = {2, 1, 3};
  std::cout << (std::strong_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::strong_order(-0.0, +0.0) < 0) << std::endl;
  std::cout << (std::strong_order(-qnan, +qnan) < 0) << std::endl;
  std::cout << (std::strong_order(+snan, +qnan) < 0) << std::endl;
  std::cout << (std::strong_order(-qnan, -snan) < 0) << std::endl;

  std::cout << "\n";

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

  std::cout << "\n";

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

出力

true

true
true
true
true

false

true

バージョン

言語

  • C++20

処理系

関連項目

参照