Skip to content

Commit 91b9997

Browse files
committed
ユーザー定義Rangeアダプタのパイプライン演算子対応 #1072
1 parent 4290e9d commit 91b9997

File tree

8 files changed

+337
-7
lines changed

8 files changed

+337
-7
lines changed

GLOBAL_DEFINED_WORDS.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,15 @@
6464
"プログラム定義型": {
6565
"desc": "標準ライブラリの型を除く、ユーザー(プログラマ)によって定義された型のこと"
6666
},
67+
"プログラム定義": {
68+
"desc": "ユーザー(プログラマ)によって定義されること(標準ライブラリで定義されるものを除く)"
69+
},
6770
"ユーザー定義型": {
6871
"redirect": "プログラム定義型"
6972
},
73+
"ユーザー定義": {
74+
"redirect": "プログラム定義"
75+
},
7076
"適格要件": {
7177
"desc": "満たさなければプログラムが不適格となる要件。`static_assert`や関数のdelete宣言などに相当する"
7278
},

GLOBAL_QUALIFY_LIST.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,9 @@
259259
* std::tie[link /reference/tuple/tie.md]
260260
* <type_traits>[link /reference/type_traits.md]
261261
* invoke_result_t[link /reference/type_traits/invoke_result.md]
262+
* is_class_v[link /reference/type_traits/is_class.md]
262263
* is_object_v[link /reference/type_traits/is_object.md]
264+
* remove_cv_t[link /reference/type_traits/remove_cv.md]
263265
* remove_cvref_t[link /reference/type_traits/remove_cvref.md]
264266
* std::false_type[link /reference/type_traits/false_type.md]
265267
* std::is_same_v[link /reference/type_traits/is_same.md]

lang/cpp23.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ C++23とは、2023年中に改訂される予定の、C++バージョンの通
141141
- Rangeを先頭に追加する`prepend_range()`メンバ関数
142142
- Rangeを末尾に追加する`append_range()`メンバ関数
143143
- Rangeを代入する`assign_range()`メンバ関数
144-
- ユーザー定義のRangeアダプタがパイプライン演算子 `|` をサポートしやすくするために、[`<ranges>`](/reference/ranges.md)[`std::ranges::range_adaptor_closure`](/reference/ranges/range_adaptor_closure.md.nolink)クラスを追加
144+
- ユーザー定義のRangeアダプタがパイプライン演算子 `|` をサポートしやすくするために、[`<ranges>`](/reference/ranges.md)[`std::ranges::range_adaptor_closure`](/reference/ranges/range_adaptor_closure.md)クラスを追加
145145
- [`<ranges>`](/reference/ranges.md)に、Rangeを連結させる[`join_with`](/reference/ranges/join_with_view.md)を追加
146146
- Rangeを指定の大きさで分割する[`std::views::chunk`](/reference/ranges/chunk_view.md)と、Rangeを指定の大きさの隣接要素で分割する[`std::views::slide`](/reference/ranges/slide_view.md)を追加
147147
- Rangeを条件一致する間の要素で分割する[`std::views::chunk_by`](/reference/ranges/chunk_by_view.md)を追加
@@ -192,7 +192,7 @@ C++23とは、2023年中に改訂される予定の、C++バージョンの通
192192
### 関数オブジェクト
193193
- [`std::invoke()`](/reference/functional/invoke.md)の戻り値型を指定するバージョンである[`std::invoke_r()`](/reference/functional/invoke_r.md)を追加
194194
- [`std::function`](/reference/functional/function.md)クラスと等価な機能をもつ、ムーブのみ可能な[`std::move_only_function`](/reference/functional/move_only_function.md)クラスを追加
195-
- ユーザー定義のRangeアダプタがパイプライン演算子 `|` をサポートしやすくするために、末尾から引数を束縛する[`std::bind_back()`](/reference/functional/bind_back.md.nolink)関数を追加
195+
- ユーザー定義のRangeアダプタがパイプライン演算子 `|` をサポートしやすくするために、末尾から引数を束縛する[`std::bind_back()`](/reference/functional/bind_back.md)関数を追加
196196

197197

198198
### メモリ

lang/cpp26.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ C++26とは、2026年中に改訂される予定の、C++バージョンの通
101101
### 関数オブジェクト
102102
- 所有権を保持しない[`std::function`](/reference/functional/function.md)として、[`<functional>`](/reference/functional.md)[`std::function_ref`](/reference/functional/function_ref.md)クラスを追加
103103
- [`std::move_only_function`](/reference/functional/move_only_function.md)のコピー可能版として、[`<functional>`](/reference/functional.md)[`std::copyable_function`](/reference/functional/copyable_function.md)クラスを追加
104-
- [`std::bind_front()`](/reference/functional/bind_front.md)[`std::bind_back()`](/reference/functional/bind_back.md.nolink)に、非型テンプレート引数として関数を指定するオーバーロードを追加
104+
- [`std::bind_front()`](/reference/functional/bind_front.md)[`std::bind_back()`](/reference/functional/bind_back.md)に、非型テンプレート引数として関数を指定するオーバーロードを追加
105105
- 関連して、非型テンプレート引数の関数オブジェクトを反転させられるよう、[`not_fn()`](/reference/functional/not_fn.md)に非型テンプレート引数版のオーバーロードを追加
106106

107107

reference/functional.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ struct doubler {
4242
| 名前 | 説明 | 対応バージョン |
4343
|----------------------------------------------------------|----------------------------------------|-------|
4444
| [`bind_front`](functional/bind_front.md) | 関数の引数を先頭から順に部分適用する(function template) | C++20 |
45+
| [`bind_back`](functional/bind_back.md) | 関数の引数を末尾から順に部分適用する(function template) | C++23 |
4546
| [`bind`](functional/bind.md) | 関数の引数を部分適用する(function template) | C++11 |
4647
| [`is_bind_expression`](functional/is_bind_expression.md) | 型を`bind`の式と見なすか判定する(class template) | C++11 |
4748
| [`is_placeholder`](functional/is_placeholder.md) | 型がプレースホルダーかどうかを判定する(class template) | C++11 |

reference/functional/bind_back.md

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
# bind_back
2+
* functional[meta header]
3+
* std[meta namespace]
4+
* function template[meta id-type]
5+
* cpp23[meta cpp]
6+
7+
```cpp
8+
namespace std {
9+
template <class F, class... Args>
10+
constexpr unspecified bind_back(F&&, Args&&...);
11+
}
12+
```
13+
* unspecified[italic]
14+
15+
## 概要
16+
関数の引数を末尾から順に部分適用する。
17+
18+
先頭から適用する場合は[`bind_front`](bind_front.md)を用いる。
19+
20+
## テンプレートパラメータ制約
21+
[`decay_t`](/reference/type_traits/decay.md)`<F>`を適用した型を`FD`、
22+
[`std::decay_t`](/reference/type_traits/decay.md)`<Args>...`を適用した型パラメータパックを`BoundArgs`であるとして、
23+
24+
- `FD`が[`std::move_constructible`](/reference/concepts/move_constructible.md)要件を満たすこと
25+
- `BoundArgs`のそれぞれの型`Ti`が[オブジェクト型](/reference/type_traits/is_object.md)である場合、[`std::move_constructible`](/reference/concepts/move_constructible.md)要件を満たすこと
26+
27+
28+
## 適格要件
29+
- [`conjunction_v`](/reference/type_traits/conjunction.md)`<`[`is_constructible`](/reference/type_traits/is_constructible.md)`<FD, F>,` [`is_move_constructible`](/reference/type_traits/is_move_constructible.md)`<FD>,` [`is_constructible`](/reference/type_traits/is_constructible.md)`<BoundArgs, Args>...,` [`is_move_constructible`](/reference/type_traits/is_move_constructible.md)`<BoundArgs>...>`が`true`であること
30+
31+
32+
## 戻り値
33+
34+
呼び出し可能な`f`を[`std::invoke()`](invoke.md)で呼び出した時に必要な引数列に後方一致する`f`と`args...`を完全転送して保持し、後から残りの引数リストを渡すことで`f`を呼び出せる未規定の関数オブジェクトを返す。
35+
36+
返される関数オブジェクトは渡された引数(`f, args...`)を参照として保持せず、適切にコピー/ムーブして保持する。
37+
38+
## 例外
39+
- 関数オブジェクト`f`のムーブによって任意の例外が送出される可能性がある
40+
41+
## この機能が必要になった背景・経緯
42+
43+
C++23で[`Rangeアダプタ`](/reference/ranges/range.md)のユーザー定義がサポートされた。
44+
45+
[`Rangeアダプタオブジェクト`](/reference/ranges/range.md)である`adaptor`が2つ以上の引数をとる場合、以下の3つの式は等しい。
46+
47+
```cpp
48+
adaptor(range, args...)
49+
adaptor(args...)(range)
50+
range | adaptor(args...)
51+
```
52+
53+
ここで、Rangeアダプタオブジェクトの第2引数以降を部分適用した結果が[`Rangeアダプタクロージャオブジェクト`](/reference/ranges/range.md)となる。
54+
ユーザー定義するRangeアダプタオブジェクトの`operator()`において、この部分適用を行うためのユーティリティとして`bind_back`が提案された。
55+
56+
##
57+
```cpp example
58+
#include <ranges>
59+
#include <vector>
60+
#include <functional>
61+
#include <print>
62+
63+
template <typename F>
64+
class closure_t : public std::ranges::range_adaptor_closure<closure_t<F>> {
65+
F f;
66+
public:
67+
constexpr closure_t(F f) : f(f) { }
68+
69+
template <std::ranges::range R>
70+
requires std::invocable<F const&, R>
71+
constexpr auto operator()(R&& r) const {
72+
return f(std::views::all(std::forward<R>(r)));
73+
}
74+
};
75+
76+
template <typename F>
77+
class adaptor_t {
78+
F f;
79+
public:
80+
constexpr adaptor_t(F f) : f(f) { }
81+
82+
template <typename... Args>
83+
constexpr auto operator()(Args&&... args) const {
84+
if constexpr (std::invocable<F const&, Args...>) {
85+
return f(std::forward<Args>(args)...);
86+
} else {
87+
return closure_t(std::bind_back(f, std::forward<Args>(args)...));
88+
}
89+
}
90+
};
91+
92+
inline constexpr closure_t user_defined_join
93+
= []<std::ranges::viewable_range R>
94+
(R&& r) {
95+
return std::ranges::join_view(std::forward<R>(r));
96+
};
97+
98+
inline constexpr adaptor_t user_defined_transform
99+
= []<std::ranges::viewable_range R, typename F>
100+
(R&& r, F&& f) {
101+
return std::ranges::transform_view(std::forward<R>(r), std::forward<F>(f));
102+
};
103+
104+
int main() {
105+
std::vector<std::vector<int>> vv = {{0, 1, 2}, {3, 4, 5}, {6}};
106+
107+
std::println("{}", vv | user_defined_join | user_defined_transform([](int x){ return x * x; }));
108+
}
109+
```
110+
* std::bind_back[color ff0000]
111+
* std::ranges::range_adaptor_closure[link /reference/ranges/range_adaptor_closure.md]
112+
* std::bind_back[link /reference/functional/bind_back.md]
113+
* std::invocable[link /reference/concepts/invocable.md]
114+
* std::views::all[link /reference/ranges/all.md]
115+
* std::ranges::range[link /reference/ranges/range.md]
116+
* std::ranges::viewable_range[link /reference/ranges/viewable_range.md]
117+
* std::ranges::join_view[link /reference/ranges/join_view.md]
118+
* std::ranges::transform_view[link /reference/ranges/transform_view.md]
119+
120+
### 出力
121+
```
122+
[0, 1, 4, 9, 16, 25, 36]
123+
```
124+
125+
## バージョン
126+
### 言語
127+
- C++23
128+
129+
### 処理系
130+
- [Clang](/implementation.md#clang): ??
131+
- [GCC](/implementation.md#gcc): ??
132+
- [ICC](/implementation.md#icc): ??
133+
- [Visual C++](/implementation.md#visual_cpp): ??
134+
135+
## 参照
136+
- [P2387R3 Pipe support for user-defined range adaptors](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2387r3.html#nanorange)
137+
- [rangesのパイプにアダプトするには](https://onihusube.hatenablog.com/entry/2022/04/24/010041)

reference/ranges.md

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,7 @@ Rangeファクトリは、Rangeではないオブジェクトから[`view`](rang
172172
173173
## Rangeアダプタ
174174
175-
Rangeアダプタは、既存のRangeに作用して新たな[`view`](ranges/view.md)を生成するものである。
176-
その実体はカスタマイゼーションポイントオブジェクトとなっている。
175+
Rangeアダプタは、既存のRangeに作用して新たなRangeを生成するものである。
177176
178177
RangeアダプタをRangeに作用させる方法には、一部の例外を除き、関数記法とパイプライン記法の2つがある。
179178
@@ -199,7 +198,14 @@ for (auto&& item : r | R) {
199198
}
200199
```
201200

202-
第1引数に[`viewable_range`](ranges/viewable_range.md)を受け取って[`view`](ranges/view.md)を返すカスタマイゼーションポイントオブジェクトを、**Rangeアダプタオブジェクト**という。とくに、1引数のものを**Rangeアダプタクロージャオブジェクト**という。
201+
**Rangeアダプタオブジェクト**は次のように定義される。
202+
203+
- 第1引数に[`viewable_range`](ranges/viewable_range.md)を受け取って[`view`](ranges/view.md)を返すカスタマイゼーションポイントオブジェクト
204+
205+
また、**Rangeアダプタクロージャオブジェクト**は次のように定義される。
206+
207+
- (C++20) [`viewable_range`](ranges/viewable_range.md)を受け取って[`view`](ranges/view.md)を返す単項関数オブジェクト
208+
- (C++23) Rangeを受け取る単項関数オブジェクト
203209

204210
Rangeアダプタオブジェクト`adaptor`が2つ以上の引数をとる場合、以下の3つの式は等しい。
205211

@@ -209,7 +215,12 @@ adaptor(args...)(range)
209215
range | adaptor(args...)
210216
```
211217
212-
このとき、`adaptor(args...)`はRangeアダプタクロージャオブジェクトになっている。
218+
このとき、式`adaptor(args...)`の値がRangeアダプタクロージャオブジェクトになっている。
219+
220+
| 名前 | 説明 | 対応バージョン |
221+
|--------------------------------------------------------------|---------------------------------------------------------------------|----------------|
222+
| [`range_adaptor_closure`](ranges/range_adaptor_closure.md) | Rangeアダプタクロージャオブジェクトの基底クラス (class template) | C++23 |
223+
213224
214225
### all view
215226

0 commit comments

Comments
 (0)