• Class / Function / Type

      std::
    • Header file

      <>
    • Other / All

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

    履歴 編集

    concept
    <compare>

    std::three_way_comparable

    namespace std {
      template<class T, class Cat = partial_ordering>
      concept three_way_comparable = /*see below*/;             // (1)
    
      template<class T, class U, class Cat = partial_ordering>
      concept three_way_comparable_with = /*see below*/;        // (2)
    }
    

    概要

    three_way_comparable及びthree_way_comparable_withは、指定された型TもしくはT, Uの間で<=>による三方比較を使用可能であり、その戻り値型が指定した比較カテゴリ型Catに変換可能であることを表すコンセプトである。

    要件

    まず、説明専用のコンセプトcompares-as及びpartially-ordered-withを以下のように定義する。

    //Catがvoidでないなら、TとCatは比較カテゴリ型でありTはCatへ変換可能である
    template<class T, class Cat>
    concept compares-as = same_as<common_comparison_category_t<T, Cat>, Cat>;
    
    //順序付けの4種×2方向の比較演算子が使用可能であり、戻り値型がboolean-testableコンセプトを満たす
    template<class T, class U>
    concept partially-ordered-with =
      requires(const remove_reference_t<T>& t, const remove_reference_t<U>& u) {
        { t <  u } -> boolean-testable;
        { t >  u } -> boolean-testable;
        { t <= u } -> boolean-testable;
        { t >= u } -> boolean-testable;
        { u <  t } -> boolean-testable;
        { u >  t } -> boolean-testable;
        { u <= t } -> boolean-testable;
        { u >= t } -> boolean-testable;
      };
    

    • (1) : 以下のように定義される。

    template<class T, class Cat = partial_ordering>
    concept three_way_comparable =
      weakly-equality-comparable-with<T, T> &&
      partially-ordered-with<T, T> &&
      requires(const remove_reference_t<T>& a, const remove_reference_t<T>& b) {
        { a <=> b } -> compares-as<Cat>;
      };
    

    • (2) : 以下のように定義される。

    template<class T, class U, class Cat = partial_ordering>
    concept three_way_comparable_with =
      three_way_comparable<T, Cat> &&
      three_way_comparable<U, Cat> &&
      common_reference_with<const remove_reference_t<T>&, const remove_reference_t<U>&> &&
      three_way_comparable<
        common_reference_t<const remove_reference_t<T>&, const remove_reference_t<U>&>, Cat> &&
      weakly-equality-comparable-with<T, U> &&
      partially-ordered-with<T, U> &&
      requires(const remove_reference_t<T>& t, const remove_reference_t<U>& u) {
        { t <=> u } -> compares-as<Cat>;
        { u <=> t } -> compares-as<Cat>;
      };
    

    モデル

    • (1) : const remove_reference_t<T>の左辺値a, bについて次の条件を満たす場合に限って、型T, Catthree_way_comparableのモデルである

      • (a <=> b == 0) == bool(a == b)trueであること
      • (a <=> b != 0) == bool(a != b)trueであること
      • ((a <=> b) <=> 0)(0 <=> (a <=> b))が等値
      • (a <=> b < 0) == bool(a < b)trueであること
      • (a <=> b > 0) == bool(a > b)trueであること
      • (a <=> b <= 0) == bool(a <= b)trueであること
      • (a <=> b >= 0) == bool(a >= b)trueであること
      • Catstrong_orderingに変換可能ならば
        • Ttotally_orderedのモデルである
    • (2) : const remove_reference_t<T>, const remove_reference_t<U>の左辺値t, uC = common_reference_t<const remove_reference_t<T>&, const remove_reference_t<U>&>について次の条件を満たす場合に限って、型T, U, Catthree_way_comparable_withのモデルである

      • t <=> uu <=> tが同じ定義域を持つ
      • ((t <=> u) <=> 0)(0 <=> (t <=> u))が等値
      • (t <=> u == 0) == bool(t == u)trueであること
      • (t <=> u != 0) == bool(t != u)trueであること
      • Cat(t <=> u) == Cat(C(t) <=> C(u))trueであること
      • (t <=> u < 0) == bool(t < u)trueであること
      • (t <=> u > 0) == bool(t > u)trueであること
      • (t <=> u <= 0) == bool(t <= u)trueであること
      • (t <=> u >= 0) == bool(t >= u)trueであること
      • Catstrong_orderingに変換可能ならば
        • T, Utotally_ordered_withのモデルである
    • partially-ordered-with : const remove_reference_t<T>, const remove_reference_t<U>の左辺値t, uについて次の条件を満たす場合に限って、型T, U, Catpartially-ordered-withのモデルである

      • t < u, t <= u, t > u, t >= u, u < t, u <= t, u > t, u >= tが全て同じ定義域を持つ
      • bool(t < u) == bool(u > t)trueであること
      • bool(u < t) == bool(t > u)trueであること
      • bool(t <= u) == bool(u >= t)trueであること
      • bool(u <= t) == bool(t >= u)trueであること

    three_way_comparable

    #include <iostream>
    #include <compare>
    
    //<=>が使用可能ならそれを使用して比較結果を出力
    template<std::three_way_comparable T>
    void print_is_less(const T& t, const T& u) {
      std::cout << "<=> : " << ((t <=> u) < 0) << std::endl;
    }
    
    //<=>が使用可能でないなら<演算子を使用
    template<typename T>
    void print_is_less(const T& t, const T& u) {
      std::cout << "<   : " << (t < u) << std::endl;
    }
    
    
    //<演算子だけが使用可能
    struct L {
      int n;
      friend bool operator<(const L& a, const L& b) { return a.n < b.n;}
    };
    
    //<=>演算子含め、全ての比較演算が可能
    struct S {
      int n;
    
      friend auto operator<=>(const S& a, const S& b) = default;
      //friend bool operator== (const S& a, const S& b) = default;
    };
    
    
    int main() {
      std::cout << std::boolalpha;
      L l1{1}, l2{2};
      S s1{1}, s2{2};
    
      print_is_less(1, 2);
      print_is_less(-0.0, +0.0);
      print_is_less(l1, l2);
      print_is_less(s1, s2);
    }
    

    出力

    <=> : true
    <=> : false
    <   : true
    <=> : true
    

    three_way_comparable_with

    #include <iostream>
    #include <compare>
    
    //<=>が使用可能ならそれを使用して比較結果を出力
    template<typename T, typename U>
    requires std::three_way_comparable_with<T, U>
    void print_is_less(const T& t, const U& u) {
      std::cout << "<=> : " << ((t <=> u) < 0) << std::endl;
    }
    
    //<=>が使用可能でないなら<演算子を使用
    template<typename T, typename U>
    void print_is_less(const T& t, const U& u) {
      std::cout << "<   : " << (t < u) << std::endl;
    }
    
    //共通の参照型を作るために必要
    struct B {
      friend auto operator<=>(const B&, const B&) = default;
      //friend bool operator== (const B&, const B&) = default;
    };
    
    struct S1 : B {
      std::size_t s;
    
      friend auto operator<=>(const S1&, const S1&) = default;
      //friend bool operator== (const S1&, const S1&) = default;
    };
    
    struct S2 : B {
      std::size_t s;
    
      friend auto operator<=>(const S2&, const S2&) = default;
      friend bool operator== (const S2&, const S2&) = default;  //この宣言は必要
    
      friend bool operator== (const S1& a, const S2& b) { return a.s ==  b.s;}
      friend auto operator<=>(const S1& a, const S2& b) { return a.s <=> b.s;}
    };
    
    //std::common_referenceおよびstd::common_reference_withにアダプトする
    namespace std {
      template<template<class> class TQual, template<class> class UQual>
      struct basic_common_reference<S1, S2, TQual, UQual> {
        using type = const B&;  //const必須
      };
    
      //対称性のために引数順を逆にしたものも定義する
      template<template<class> class TQual, template<class> class UQual>
      struct basic_common_reference<S2, S1, TQual, UQual> {
        using type = const B&;  //const必須
      };
    }
    
    
    int main() {
      std::cout << std::boolalpha;
      S1 s1{{}, 0u};
      S2 s2{{}, 2u};
    
      print_is_less(s1, s2);
      print_is_less(s2, s1);
    }
    

    出力

    <=> : true
    <=> : false
    

    バージョン

    言語

    • C++20

    処理系

    関連項目

    参照