Skip to content

Commit 28212cc

Browse files
committed
compare : C++26対応としてtype_orderを追加 (close #1506)
1 parent 19c2903 commit 28212cc

5 files changed

Lines changed: 153 additions & 2 deletions

File tree

lang/cpp26.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,7 @@ C++26とは、2026年中に改訂される予定の、C++バージョンの通
512512
- [`<memory>`](/reference/memory.md)に、ポインタのアライメントを判定する[`std::is_sufficiently_aligned()`](/reference/memory/is_sufficiently_aligned.md)関数を追加。
513513
- [`<utility>`](/reference/utility.md)に、タイムトラベル最適化を抑止するための観測可能ポイントとして[`std::observable_checkpoint()`](/reference/utility/observable_checkpoint.md)を追加
514514
- [`std::exception_ptr`](/reference/exception/exception_ptr.md)を指定した例外型にキャストする[`std::exception_ptr_cast()`](/reference/exception/exception_ptr_cast.md)関数を追加
515-
- [`<compare>`](/reference/compare.md)に、型の順序を取得する[`std::type_order`](/reference/compare/type_order.md.nolink)クラスを追加
515+
- [`<compare>`](/reference/compare.md)に、型の順序を取得する[`std::type_order`](/reference/compare/type_order.md)クラスを追加
516516

517517

518518
### デバッグ

lang/cpp26/feature_test_macros.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@
158158
|`__cpp_lib_to_string`|`202306L`|[`std::to_string`](/reference/string/to_string.md)の変換結果を`sprintf()`ベースから`std::format()`ベースに変更|[`<string>`](/reference/string.md)|
159159
|`__cpp_lib_trivially_relocatable`|`202502L`|トリビアルな再配置|[`<memory>`](/reference/memory.md), [`<type_traits>`](/reference/type_traits.md)|
160160
|`__cpp_lib_tuple_like`|`202311L`|[`std::complex`](/reference/complex/complex.md)にタプルインタフェースの特殊化を追加|[`<utility>`](/reference/utility.md), [`<tuple>`](/reference/tuple.md), [`<map>`](/reference/map.md), [`<unordered_map>`](/reference/unordered_map.md)|
161-
|`__cpp_lib_type_order`|`202506L`|[`std::type_info::before`](/reference/typeinfo/type_info/before.md)のconstexpr化|[`<compare>`](/reference/compare.md)|
161+
|`__cpp_lib_type_order`|`202506L`|[`std::type_order`](/reference/compare/type_order.md)を追加|[`<compare>`](/reference/compare.md)|
162162
|`__cpp_lib_variant`|`202306L`|[`std::variant`](/reference/variant/variant.md)クラスに、メンバ関数版の[`visit()`](/reference/variant/variant/visit.md)を追加|[`<variant>`](/reference/variant.md)|
163163

164164
実装依存のマクロ。

reference/compare.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@
3535
| [`common_comparison_category`](compare/common_comparison_category.md) | 指定された全ての型の共通比較カテゴリ型を求める | C++20 |
3636
| [`compare_three_way_result`](compare/compare_three_way_result.md) | 指定された型の間での`<=>`による比較結果の型を求める | C++20 |
3737

38+
39+
## 型の順序
40+
41+
| 名前 | 説明 | 対応バージョン |
42+
| ------------------------------------- | ------------------------------------------------- | -------------- |
43+
| [`type_order`](compare/type_order.md) | 2つの型の間の実装定義の全順序を取得する (class template) | C++26 |
44+
3845
## コンセプト
3946

4047
| 名前 | 説明 | 対応バージョン |

reference/compare/type_order.md

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# type_order
2+
* compare[meta header]
3+
* std[meta namespace]
4+
* class template[meta id-type]
5+
* cpp26[meta cpp]
6+
7+
```cpp
8+
namespace std {
9+
template <class T, class U>
10+
struct type_order {
11+
static constexpr strong_ordering value = TYPE-ORDER(T, U); // 説明専用
12+
13+
using value_type = strong_ordering;
14+
15+
constexpr operator value_type() const noexcept { return value; }
16+
constexpr value_type operator()() const noexcept { return value; }
17+
};
18+
19+
template <class T, class U>
20+
constexpr strong_ordering type_order_v = type_order<T, U>::value;
21+
}
22+
```
23+
* strong_ordering[link strong_ordering.md]
24+
25+
## 概要
26+
2つの型`T``U`の間の、コンパイル時の全順序を取得する。
27+
28+
これを使用することにより、型リストの正規化(例えば`typeset<A, B>``typeset<B, A>`を同じ型として扱う)や、複数の翻訳単位にわたって型の順序を一貫させることができる。
29+
30+
31+
## 効果
32+
`TYPE-ORDER(T, U)`は実装定義であり、すべての型に対する全順序を表す。以下の保証がある:
33+
34+
- 反射律: `type_order_v<T, T>`[`strong_ordering::equal`](strong_ordering.md)
35+
- 反対称律: `type_order_v<T, U>``less`であれば、`type_order_v<U, T>``greater`
36+
- 推移律: 通常の推移性
37+
- CV修飾や参照修飾の異なる型は別個の型として区別される(例: `int``const int``int&`は順序として`equal`ではない)
38+
39+
実装は、型の同名異シグニチャ化に使用される既存のABIマングリング基盤を利用することが想定される。実装は推奨事項として、テンプレートの第i引数のみが異なる場合に、`X<...,T,...>``X<...,U,...>`の順序が`T``U`の順序と一致するように再帰的な一貫性を提供することができる。
40+
41+
42+
## 備考
43+
- C++26より前は、型の全順序を得るためには`__PRETTY_FUNCTION__`等の処理系固有の機能を使うか、`typeid`を実行時に比較する必要があった。`type_order`は、コンパイル時に取得できる、実装定義であるが安定した型の全順序を提供する
44+
- このクラスは不完全型に対しても動作する
45+
- 実装定義の全順序の具体的な順番には依存すべきではないが、同じ実装のなかでは翻訳単位の境界をまたいでも安定する
46+
47+
48+
##
49+
```cpp example
50+
#include <compare>
51+
#include <type_traits>
52+
53+
struct A {};
54+
struct B {};
55+
56+
int main() {
57+
// 同じ型同士の比較はequal
58+
static_assert(std::type_order_v<int, int> == std::strong_ordering::equal);
59+
60+
// 異なる型同士の順序は実装定義だが、反対称性は保証される
61+
constexpr auto ord_ab = std::type_order_v<A, B>;
62+
constexpr auto ord_ba = std::type_order_v<B, A>;
63+
static_assert(ord_ab != std::strong_ordering::equal);
64+
static_assert((ord_ab < 0) == (ord_ba > 0));
65+
static_assert((ord_ab > 0) == (ord_ba < 0));
66+
67+
// CV修飾の違いも区別される
68+
static_assert(std::type_order_v<int, const int> != std::strong_ordering::equal);
69+
}
70+
```
71+
72+
### 出力
73+
```
74+
```
75+
76+
77+
## バージョン
78+
### 言語
79+
- C++26
80+
81+
### 処理系
82+
- [Clang](/implementation.md#clang): 22 [mark noimpl]
83+
- [GCC](/implementation.md#gcc): 16 [mark verified]
84+
- [Visual C++](/implementation.md#visual_cpp): 2026 Update 2 [mark noimpl]
85+
86+
87+
## 関連項目
88+
- [`strong_ordering`](strong_ordering.md)
89+
- [`std::meta::type_order`](/reference/meta/type_order.md)
90+
91+
92+
## 参照
93+
- [P2830R10 Constexpr Type Ordering](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2830r10.html)
94+
- [P3778R0 Fix for `type_order` template definition](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3778r0.html)

reference/meta/type_order.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ namespace std::meta {
1414
## 概要
1515
2つの型のリフレクション間の順序を取得する。[`std::meta::info`](info.md)は`<=>`をサポートしないが、この関数により型のリフレクション間で一貫した全順序を得ることができる。
1616
17+
[`std::type_order`](/reference/compare/type_order.md)のリフレクション版である。
18+
1719
1820
## 戻り値
1921
`type_a`と`type_b`が型を表す場合、それらの間の実装定義の全順序を[`strong_ordering`](/reference/compare/strong_ordering.md)として返す。
@@ -23,7 +25,19 @@ namespace std::meta {
2325
`type_a`または`type_b`が型を表さない場合、[`std::meta::exception`](exception.md)例外を送出する。
2426
2527
28+
## 備考
29+
型のリフレクションを並べ替えるユースケースで使用される。具体的には以下のような場面で必要になる:
30+
31+
- **型リストの正規化**: 型集合(`typeset<A, B>`と`typeset<B, A>`を同じ型にする)の実装
32+
- **`std::variant`の候補型の正規化**: 候補型の順序を一意化することで、`variant<A, B>`と`variant<B, A>`を同じ型として扱える
33+
- **`std::expected`のエラー型の集約**: 複数の翻訳単位にわたって安定したエラー型のマージ
34+
- **`std::execution`等の非同期処理**: 中継型を一意化することで安定したシグニチャを得る
35+
36+
実装定義の全順序の具体的な順番には依存すべきではないが、ある実装の中では翻訳単位の境界をまたいでも安定する。
37+
38+
2639
## 例
40+
### 基本的な使い方
2741
```cpp example
2842
#include <meta>
2943
#include <compare>
@@ -40,6 +54,42 @@ int main() {
4054
```
4155
```
4256

57+
### 型リフレクションを順序付けする
58+
[`type_order()`](type_order.md)を比較関数として使用することで、型リフレクションのコレクションを安定した順序にソートできる。
59+
60+
```cpp example
61+
#include <meta>
62+
#include <algorithm>
63+
#include <vector>
64+
65+
consteval std::vector<std::meta::info> sort_types(std::vector<std::meta::info> types) {
66+
std::ranges::sort(types,
67+
[](std::meta::info a, std::meta::info b) {
68+
return std::meta::type_order(a, b) == std::strong_ordering::less;
69+
});
70+
return types;
71+
}
72+
73+
int main() {
74+
// 入力順序に関わらず、同じ型集合は同じ並びにソートされる
75+
static constexpr auto sorted1 = std::define_static_array(
76+
sort_types({^^int, ^^double, ^^char}));
77+
static constexpr auto sorted2 = std::define_static_array(
78+
sort_types({^^char, ^^int, ^^double}));
79+
80+
// 並びが一致することを確認
81+
static_assert(sorted1.size() == sorted2.size());
82+
static_assert(sorted1[0] == sorted2[0]);
83+
static_assert(sorted1[1] == sorted2[1]);
84+
static_assert(sorted1[2] == sorted2[2]);
85+
}
86+
```
87+
* std::ranges::sort[link /reference/algorithm/ranges_sort.md]
88+
89+
### 出力
90+
```
91+
```
92+
4393
4494
## バージョン
4595
### 言語

0 commit comments

Comments
 (0)