Skip to content

Commit f222955

Browse files
committed
fold_left_with_iter追加 #1088
1 parent 7c5eb19 commit f222955

File tree

8 files changed

+330
-8
lines changed

8 files changed

+330
-8
lines changed

lang/cpp23.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ C++23とは、2023年中に改訂される予定の、C++バージョンの通
164164
- [`std::ranges::fold_left_first()`](/reference/algorithm/ranges_fold_left_first.md)
165165
- [`std::ranges::fold_right()`](/reference/algorithm/ranges_fold_right.md)
166166
- [`std::ranges::fold_right_last()`](/reference/algorithm/ranges_fold_right_last.md)
167-
- [`std::ranges::fold_left_with_iter()`](/reference/algorithm/ranges_fold_left_with_iter.md.nolink)
167+
- [`std::ranges::fold_left_with_iter()`](/reference/algorithm/ranges_fold_left_with_iter.md)
168168
- [`std::ranges::fold_left_first_with_iter()`](/reference/algorithm/ranges_fold_left_first_with_iter.md.nolink)
169169
- [`<numeric>`](/reference/numeric.md)に、連番を生成するRangeアルゴリズム[`std::ranges::iota()`](/reference/numeric/ranges_iota.md)を追加
170170

reference/algorithm.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ ranges::sort(pv, {}, &Parson::name);
430430
| [`ranges::fold_right`](algorithm/ranges_fold_right.md)| 範囲の右(終端)からの`fold` | C++23 |
431431
| [`ranges::fold_left_first`](algorithm/ranges_fold_left_first.md)| 範囲の左(先頭)からの`fold`、初期値を省略する | C++23 |
432432
| [`ranges::fold_right_last`](algorithm/ranges_fold_right_last.md)| 範囲の右(終端)からの`fold`、初期値を省略する | C++23 |
433-
| [`ranges::fold_left_with_iter`](algorithm/ranges_fold_left_with_iter.md.nolink) | 範囲の左(先頭)からの`fold`、終端イテレータを返す | C++23 |
433+
| [`ranges::fold_left_with_iter`](algorithm/ranges_fold_left_with_iter.md) | 範囲の左(先頭)からの`fold`、終端イテレータを返す | C++23 |
434434
| [`ranges::fold_left_first_with_iter`](algorithm/ranges_fold_left_first_with_iter.md.nolink) | 範囲の左(先頭)からの`fold`、初期値を省略し終端イテレータを返す | C++23 |
435435
436436
### 戻り値
@@ -446,6 +446,7 @@ ranges::sort(pv, {}, &Parson::name);
446446
| [`ranges::in_out_out_result`](algorithm/ranges_in_out_out_result.md) | 3つのイテレータを格納する型 | C++20 |
447447
| [`ranges::min_max_result`](algorithm/ranges_min_max_result.md) | 2つの値または参照を格納する型 | C++20 |
448448
| [`ranges::in_found_result`](algorithm/ranges_in_found_result.md) | イテレータとbool値を格納する型 | C++20 |
449+
| [`ranges::in_value_result`](algorithm/ranges_in_value_result.md) | イテレータと値を格納する型 | C++23 |
449450
| [`ranges::out_value_result`](algorithm/ranges_out_value_result.md) | イテレータと値を格納する型 | C++23 |
450451
451452

reference/algorithm/ranges_fold_left.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ concept indirectly-binary-left-foldable =
100100
```cpp
101101
return ranges::fold_left_with_iter(std::move(first), last, std::move(init), f).value;
102102
```
103-
* fold_left_with_iter[link /reference/algorithm/ranges_fold_left_with_iter.md.nolink]
103+
* fold_left_with_iter[link /reference/algorithm/ranges_fold_left_with_iter.md]
104104

105105
- (2) : `r`からイテレータを取得して(1)に委譲
106106
```cpp
@@ -264,7 +264,7 @@ constexpr auto fold_left(I first, S last, T init, F f) {
264264
- 範囲の最初の要素を初期値として`fold_left`
265265
- [`ranges::fold_right_last`](ranges_fold_right_last.md)
266266
- 範囲の最後の要素を初期値として`fold_right`
267-
- [`ranges::fold_left_with_iter`](ranges_fold_left_with_iter.md.nolink)
267+
- [`ranges::fold_left_with_iter`](ranges_fold_left_with_iter.md)
268268
- `fold_left`の結果と共に、計算した終端イテレータも返す
269269
- [`ranges::fold_left_first_with_iter`](ranges_fold_left_first_with_iter.md.nolink)
270270
- `fold_left_first`の結果と共に、計算した終端イテレータも返す

reference/algorithm/ranges_fold_left_first.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ int main() {
150150
}
151151
```
152152
* fold_left_first[color ff0000]
153-
* fold_left[link ranges_fold_right.md]
153+
* fold_left[link ranges_fold_left.md]
154154
* println[link /reference/print/println.md]
155155
* value_or[link /reference/optional/optional/value_or.md]
156156

@@ -202,7 +202,7 @@ constexpr auto fold_left_first(I first, S last, F f) {
202202
- 範囲の右からの`fold`
203203
- [`ranges::fold_right_last`](ranges_fold_right_last.md)
204204
- 範囲の最後の要素を初期値として`fold_right`
205-
- [`ranges::fold_left_with_iter`](ranges_fold_left_with_iter.md.nolink)
205+
- [`ranges::fold_left_with_iter`](ranges_fold_left_with_iter.md)
206206
- `fold_left`の結果と共に、計算した終端イテレータも返す
207207
- [`ranges::fold_left_first_with_iter`](ranges_fold_left_first_with_iter.md.nolink)
208208
- `fold_left_first`の結果と共に、計算した終端イテレータも返す
Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
# fold_left_first
2+
* algorithm[meta header]
3+
* function template[meta id-type]
4+
* std::ranges[meta namespace]
5+
* cpp23[meta cpp]
6+
7+
```cpp
8+
namespace std::ranges {
9+
template<input_iterator I, sentinel_for<I> S, class T,
10+
indirectly-binary-left-foldable<T, I> F>
11+
constexpr auto fold_left_with_iter(I first, S last, T init, F f); // (1)
12+
13+
template<input_range R, class T,
14+
indirectly-binary-left-foldable<T, iterator_t<R>> F>
15+
constexpr auto fold_left_with_iter(R&& r, T init, F f); // (2)
16+
}
17+
```
18+
* input_iterator[link /reference/iterator/input_iterator.md]
19+
* sentinel_for[link /reference/iterator/sentinel_for.md]
20+
* indirectly-binary-left-foldable[link ./ranges_fold_left.md]
21+
* input_range[link /reference/ranges/input_range.md]
22+
* iterator_t[link /reference/ranges/iterator_t.md]
23+
24+
## 概要
25+
26+
処理の過程で得られた終端位置を指すイテレータを同時に返す[`fold_left`](./ranges_fold_left.md)。戻り値はイテレータと処理結果のペアとなる。
27+
28+
- (1) : 入力としてイテレータ範囲をとるオーバーロード
29+
- (2) : 入力として範囲を直接とるオーバーロード
30+
31+
## 引数
32+
33+
- `first` -- 入力範囲の先頭イテレータ
34+
- `last` -- 入力範囲の番兵(終端イテレータ)
35+
- `r` -- 入力範囲のオブジェクト
36+
- `init` -- 初期値
37+
- `f` -- 適用する二項演算
38+
- `f(std::move(init), *first)`のような呼び出しが可能であり、その戻り値型のオブジェクトを`acc`とすると
39+
- `acc = f(std::move(acc), *first)`のような呼び出しも可能である必要がある
40+
41+
## テンプレートパラメータ制約
42+
43+
二項演算(`F`)は初期値・積算値と入力範囲の参照型に対して[`invocable`](/reference/concepts/invocable.md)であることしか求められていない(`regular_invocable`ではない)ため、適用する二項演算は任意の副作用を伴っていても良い。
44+
45+
## 戻り値
46+
47+
型`U`を次のように取得して
48+
49+
```cpp
50+
using U = decay_t<invoke_result_t<F&, T, iter_reference_t<I>>>;
51+
```
52+
* decay_t[link /reference/type_traits/decay.md]
53+
* invoke_result_t[link /reference/type_traits/invoke_result.md]
54+
* iter_reference_t[link /reference/iterator/iter_reference_t.md]
55+
56+
(1)(2)ともに、以下と等価
57+
58+
```cpp
59+
if (first == last)
60+
return {std::move(first), U(std::move(init))};
61+
U accum = invoke(f, std::move(init), *first);
62+
for (++first; first != last; ++first)
63+
accum = invoke(f, std::move(accum), *first);
64+
return {std::move(first), std::move(accum)};
65+
```
66+
* decay_t[link /reference/type_traits/decay.md]
67+
* invoke_result_t[link /reference/type_traits/invoke_result.md]
68+
* iter_reference_t[link /reference/iterator/iter_reference_t.md]
69+
* next[link /reference/iterator/ranges_next.md]
70+
* invoke[link /reference/functional/invoke.md]
71+
72+
空の入力範囲に対しては初期値`init`を返す。入力範囲によらず、戻り値の1つ目の値(イテレータ値)は渡した範囲の終端イテレータ(`last`/`ranges::end(r)`)と同じ位置を指すイテレータとなる(必ずしも同じ型もしくは同じイテレータにならない)。
73+
74+
戻り値型はそれぞれ、`U`を次の様に[`fold_left_with_iter_result`](/reference/algorithm/ranges_in_value_result.md)の2つ目の引数に当てはめた型となる
75+
76+
```cpp
77+
template<input_iterator I, sentinel_for<I> S, class T,
78+
indirectly-binary-left-foldable<T, I> F>
79+
constexpr fold_left_with_iter_result<I, U>
80+
fold_left_with_iter(I first, S last, T init, F f);
81+
82+
template<input_range R, class T,
83+
indirectly-binary-left-foldable<T, iterator_t<R>> F>
84+
constexpr fold_left_with_iter_result<borrowed_iterator_t<R>, U>
85+
fold_left_with_iter(R&& r, T init, F f);
86+
```
87+
* fold_left_with_iter_result[link /reference/algorithm/ranges_in_value_result.md]
88+
* borrowed_iterator_t[link /reference/ranges/borrowed_iterator_t.md]
89+
90+
1つ目の引数には入力のイテレータ型が当てられる。
91+
92+
## 計算量
93+
94+
入力範囲`r``[first, last)`)の要素数を`N`とすると、正確に`N`回の`f`の適用が行われる。
95+
96+
## 備考
97+
98+
戻り値の項で使用している`U`は、指定した二項演算を初期値とイテレータによって`f(std::move(init), *first)`のように呼び出した時の戻り値型であり、`fold_left_with_iter()`の処理内部で積算値の型として使用されるものでもある。
99+
100+
`fold_left`同様に、`f``init`の代わりに`U`の右辺値も受け取れる必要がある。二項演算の呼び出しにおいては、第一引数に初期値もしくは積算値が渡され、第二引数にイテレータの間接参照結果が直接渡される。そして、二項演算の適用結果は積算値を保存する変数に直接代入される(つまり、結果を次のステップに引き継ぎたい場合は積算処理も二項演算内で行う必要がある)。詳細は下の実装例を参照。
101+
102+
##
103+
104+
### 基本的な数値集計処理の例
105+
106+
```cpp example
107+
#include <ranges>
108+
#include <algorithm>
109+
#include <functional>
110+
#include <print>
111+
#include <vector>
112+
113+
using namespace std::ranges;
114+
115+
int main() {
116+
// 入力
117+
range auto rng = views::iota(1, 11);
118+
// 初期値
119+
const int init = 0;
120+
// 二項演算
121+
auto op = std::plus<>{};
122+
123+
auto [end1, resl] = fold_left_with_iter(rng, init, op);
124+
125+
std::println("{{ {:s}, {:d} }}", end1 == end(rng), resl);
126+
127+
128+
// 入力範囲はfloatのvector
129+
std::vector<float> rngf = { 0.125f, 0.25f, 0.75f };
130+
131+
// 計算結果はfloat
132+
auto [end2, reslf] = fold_left_with_iter(rngf, init, op);
133+
134+
std::println("{{ {:s}, {:g} }}", end2 == end(rngf), reslf);
135+
}
136+
```
137+
* fold_left_with_iter[color ff0000]
138+
* iota[link /reference/ranges/iota_view.md]
139+
* plus[link /reference/functional/plus.md]
140+
* println[link /reference/print/println.md]
141+
142+
### 出力
143+
```
144+
{ true, 55 }
145+
{ true, 1.125 }
146+
```
147+
148+
### 空の入力範囲に対する動作の例
149+
150+
```cpp example
151+
#include <ranges>
152+
#include <algorithm>
153+
#include <functional>
154+
#include <print>
155+
#include <vector>
156+
157+
using namespace std::ranges;
158+
159+
int main() {
160+
range auto rng = views::empty<int>;
161+
const int init = -1;
162+
auto op = std::plus<>{};
163+
164+
auto res1 = fold_left(rng, init, op);
165+
auto res2 = fold_left_first(rng, op);
166+
auto [_, res3] = fold_left_with_iter(rng, init, op);
167+
168+
std::println("{:d}", res1);
169+
std::println("{:d}", res2.value_or(-1));
170+
std::println("{:d}", res3);
171+
}
172+
```
173+
* fold_left_with_iter[color ff0000]
174+
* fold_left[link ranges_fold_left.md]
175+
* fold_left_first[link ranges_fold_left_first.md]
176+
* println[link /reference/print/println.md]
177+
* value_or[link /reference/optional/optional/value_or.md]
178+
179+
### 出力
180+
```
181+
-1
182+
-1
183+
-1
184+
```
185+
186+
## 実装例
187+
188+
```cpp
189+
template<input_iterator I, sentinel_for<I> S, class T,
190+
indirectly-binary-left-foldable<T, I> F>
191+
constexpr auto fold_left_with_iter(I first, S last, F f) -> fold_left_with_iter_result<I, U> {
192+
using U = decay_t<invoke_result_t<F&, T, iter_reference_t<I>>>;
193+
194+
if (first == last) {
195+
return {std::move(first), U(std::move(init))};
196+
}
197+
198+
U accum = invoke(f, std::move(init), *first);
199+
200+
++first;
201+
202+
for (; first != last; ++first) {
203+
accum = invoke(f, std::move(accum), *first);
204+
}
205+
206+
return {std::move(first), std::move(accum)};
207+
}
208+
```
209+
210+
## バージョン
211+
### 言語
212+
- C++23
213+
214+
### 処理系
215+
- [Clang](/implementation.md#clang): ??
216+
- [GCC](/implementation.md#gcc): 13.1
217+
- [Visual C++](/implementation.md#visual_cpp): 2022 Update 5
218+
219+
## 関連項目
220+
221+
- [`ranges::fold_left`](ranges_fold_left.md)
222+
- 範囲の左からの`fold`
223+
- [`ranges::fold_right`](ranges_fold_right.md)
224+
- 範囲の右からの`fold`
225+
- [`ranges::fold_left_first`](ranges_fold_left_first.md)
226+
- 範囲の最初の要素を初期値として`fold_left`
227+
- [`ranges::fold_right_last`](ranges_fold_right_last.md)
228+
- 範囲の最後の要素を初期値として`fold_right`
229+
- [`ranges::fold_left_first_with_iter`](ranges_fold_left_first_with_iter.md.nolink)
230+
- `fold_left_first`の結果と共に、計算した終端イテレータも返す
231+
232+
## 参照
233+
234+
- [P2322R6 `ranges::fold`](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2322r6.html)

reference/algorithm/ranges_fold_right.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ constexpr auto fold_right(I first, S last, T init, F f) {
300300
- 範囲の最初の要素を初期値として`fold_left`
301301
- [`ranges::fold_right_last`](ranges_fold_right_last.md)
302302
- 範囲の最後の要素を初期値として`fold_right`
303-
- [`ranges::fold_left_with_iter`](ranges_fold_left_with_iter.md.nolink)
303+
- [`ranges::fold_left_with_iter`](ranges_fold_left_with_iter.md)
304304
- `fold_left`の結果と共に、計算した終端イテレータも返す
305305
- [`ranges::fold_left_first_with_iter`](ranges_fold_left_first_with_iter.md.nolink)
306306
- `fold_left_first`の結果と共に、計算した終端イテレータも返す

reference/algorithm/ranges_fold_right_last.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ constexpr auto fold_right_last(I first, S last, F f) {
215215
- 範囲の右からの`fold`
216216
- [`ranges::fold_left_first`](ranges_fold_left_first.md)
217217
- 範囲の最初の要素を初期値として`fold_left`
218-
- [`ranges::fold_left_with_iter`](ranges_fold_left_with_iter.md.nolink)
218+
- [`ranges::fold_left_with_iter`](ranges_fold_left_with_iter.md)
219219
- `fold_left`の結果と共に、計算した終端イテレータも返す
220220
- [`ranges::fold_left_first_with_iter`](ranges_fold_left_first_with_iter.md.nolink)
221221
- `fold_left_first`の結果と共に、計算した終端イテレータも返す

0 commit comments

Comments
 (0)