Skip to content

Commit b9c8967

Browse files
committed
fold_right_last追加 #1088
1 parent 50d9d18 commit b9c8967

File tree

6 files changed

+230
-12
lines changed

6 files changed

+230
-12
lines changed

lang/cpp23.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ C++23とは、2023年中に改訂される予定の、C++バージョンの通
163163
- [`std::ranges::fold_left()`](/reference/algorithm/ranges_fold_left.md)
164164
- [`std::ranges::fold_left_first()`](/reference/algorithm/ranges_fold_left_first.md)
165165
- [`std::ranges::fold_right()`](/reference/algorithm/ranges_fold_right.md)
166-
- [`std::ranges::fold_right_last()`](/reference/algorithm/ranges_fold_right_last.md.nolink)
166+
- [`std::ranges::fold_right_last()`](/reference/algorithm/ranges_fold_right_last.md)
167167
- [`std::ranges::fold_left_with_iter()`](/reference/algorithm/ranges_fold_left_with_iter.md.nolink)
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)を追加

reference/algorithm.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,7 @@ ranges::sort(pv, {}, &Parson::name);
429429
| [`ranges::fold_left`](algorithm/ranges_fold_left.md) | 範囲の左(先頭)からの`fold` | C++23 |
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 |
432-
| [`ranges::fold_right_last`](algorithm/ranges_fold_right_last.md.nolink)| 範囲の右(終端)からの`fold`、初期値を省略する | C++23 |
432+
| [`ranges::fold_right_last`](algorithm/ranges_fold_right_last.md)| 範囲の右(終端)からの`fold`、初期値を省略する | C++23 |
433433
| [`ranges::fold_left_with_iter`](algorithm/ranges_fold_left_with_iter.md.nolink) | 範囲の左(先頭)からの`fold`、終端イテレータを返す | C++23 |
434434
| [`ranges::fold_left_first_with_iter`](algorithm/ranges_fold_left_first_with_iter.md.nolink) | 範囲の左(先頭)からの`fold`、初期値を省略し終端イテレータを返す | C++23 |
435435

reference/algorithm/ranges_fold_left.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ namespace std::ranges {
5555
- `init` -- 初期値
5656
- `f` -- 適用する二項演算
5757
- `f(std::move(init), *first)`のような呼び出しが可能であり、その戻り値型のオブジェクトを`acc`とすると
58-
- `f(std::move(acc), *first)`のような呼び出しも可能である必要がある
58+
- `acc = f(std::move(acc), *first)`のような呼び出しも可能である必要がある
5959
6060
## テンプレートパラメータ制約
6161

reference/algorithm/ranges_fold_left_first.md

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ namespace std::ranges {
4141
- `last` -- 入力範囲の番兵(終端イテレータ)
4242
- `r` -- 入力範囲のオブジェクト
4343
- `f` -- 適用する二項演算
44-
- `f(std::move(*first), *++first)`のような呼び出しが可能であり、その戻り値型のオブジェクトを`acc`とすると
45-
- `f(std::move(acc), *first)`のような呼び出しも可能である必要がある
44+
- `f(*first, *first)`のような呼び出しが可能であり(実際にこの様に呼ばれるわけではない)、その戻り値型のオブジェクトを`acc`とすると
45+
- `acc = f(std::move(acc), *first)`のような呼び出しも可能である必要がある
4646
4747
## 戻り値
4848
@@ -75,9 +75,9 @@ using U = decltype(ranges::fold_left(std::move(first), last, iter_value_t<I>(*fi
7575
* fold_left[link ./ranges_fold_left.md]
7676
* iter_value_t[link /reference/iterator/iter_value_t.md]
7777

78-
すなわち、他の引数はそのままに初期値として`r`の要素を手動で指定して`fold_left`を呼び出した際の戻り値型を包む`optional`となる。
78+
すなわち、他の引数はそのままに初期値として入力範囲`r`の要素を手動で指定して`fold_left`を呼び出した際の戻り値型を包む`optional`となる。
7979

80-
`fold_left`と同様に、この型`U``fold_left_first`の処理内部で積算値の型として使用されるものでもあり、`f``std::move(*first)`の代わりに`U`の右辺値も受け取れる必要がある。詳細は下の実装例を参照。
80+
`fold_left`と同様に、この型`U``fold_left_first`の処理内部で積算値の型として使用されるものでもあり、`f``*first`の代わりに`U`の右辺値も受け取れる必要がある。詳細は下の実装例を参照。
8181

8282
##
8383

@@ -139,10 +139,10 @@ int main() {
139139
auto op = std::plus<>{};
140140
141141
auto res1 = fold_left(rng, -1, op);
142-
auto res3 = fold_left_first(rng, op);
142+
auto res2 = fold_left_first(rng, op);
143143
144144
std::println("{:d}", res1);
145-
std::println("{:d}", res3.value_or(-1));
145+
std::println("{:d}", res2.value_or(-1));
146146
}
147147
```
148148
* fold_left_first[color ff0000]
@@ -196,7 +196,7 @@ constexpr auto fold_left_first(I first, S last, F f) {
196196
- 範囲の左からの`fold`
197197
- [`ranges::fold_right`](ranges_fold_right.md)
198198
- 範囲の右からの`fold`
199-
- [`ranges::fold_right_last`](ranges_fold_right_last.md.nolink)
199+
- [`ranges::fold_right_last`](ranges_fold_right_last.md)
200200
- 範囲の最後の要素を初期値として`fold_right`
201201
- [`ranges::fold_left_with_iter`](ranges_fold_left_with_iter.md.nolink)
202202
- `fold_left`の結果と共に、計算した終端イテレータも返す
@@ -206,4 +206,3 @@ constexpr auto fold_left_first(I first, S last, F f) {
206206
## 参照
207207
208208
- [P2322R6 `ranges::fold`](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2322r6.html)
209-
- [プログラミングHaskellのfoldr, foldlの説明が秀逸だった件 - あと味](https://taiju.hatenablog.com/entry/20130202/1359773888)

reference/algorithm/ranges_fold_right.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ namespace std::ranges {
5555
- `init` -- 初期値
5656
- `f` -- 適用する二項演算
5757
- `f(*first, std::move(init))`のような呼び出しが可能であり、その戻り値型のオブジェクトを`acc`とすると
58-
- `f(*first, std::move(acc))`のような呼び出しも可能である必要がある
58+
- `acc = f(*first, std::move(acc))`のような呼び出しも可能である必要がある
5959
6060
## テンプレートパラメータ制約
6161
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
# fold_right_last
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<bidirectional_iterator I, sentinel_for<I> S,
10+
indirectly-binary-right-foldable<iter_value_t<I>, I> F>
11+
requires constructible_from<iter_value_t<I>, iter_reference_t<I>>
12+
constexpr auto fold_right_last(I first, S last, F f); // (1)
13+
14+
template<bidirectional_range R,
15+
indirectly-binary-right-foldable<range_value_t<R>, iterator_t<R>> F>
16+
requires constructible_from<range_value_t<R>, range_reference_t<R>>
17+
constexpr auto fold_right_last(R&& r, F f); // (2)
18+
}
19+
```
20+
* bidirectional_iterator[link /reference/iterator/bidirectional_iterator.md]
21+
* sentinel_for[link /reference/iterator/sentinel_for.md]
22+
* constructible_from[link /reference/concepts/constructible_from.md]
23+
* iter_value_t[link /reference/iterator/iter_value_t.md]
24+
* iter_reference_t[link /reference/iterator/iter_reference_t.md]
25+
* bidirectional_range[link /reference/ranges/bidirectional_range.md]
26+
* range_value_t[link /reference/ranges/range_value_t.md]
27+
* range_reference_t[link /reference/ranges/range_reference_t.md]
28+
* iterator_t[link /reference/ranges/iterator_t.md]
29+
* indirectly-binary-right-foldable[link ./ranges_fold_right.md]
30+
31+
## 概要
32+
33+
初期値の指定を省略する[`fold_right`](./ranges_fold_right.md)。入力範囲の末尾要素が初期値として使用される。
34+
35+
- (1) : 入力としてイテレータ範囲をとるオーバーロード
36+
- (2) : 入力として範囲を直接とるオーバーロード
37+
38+
## 引数
39+
40+
- `first` -- 入力範囲の先頭イテレータ
41+
- `last` -- 入力範囲の番兵(終端イテレータ)
42+
- `r` -- 入力範囲のオブジェクト
43+
- `f` -- 適用する二項演算
44+
- `f(*first, *first)`のような呼び出しが可能であり(実際にこの様に呼ばれるわけではない)、その戻り値型のオブジェクトを`acc`とすると
45+
- `acc = f(*first, std::move(acc))`のような呼び出しも可能である必要がある
46+
47+
## 戻り値
48+
49+
(1)(2)ともに、以下と等価
50+
51+
```cpp
52+
using U = decay_t<invoke_result_t<F&, iter_reference_t<I>, T>>;
53+
if (first == last)
54+
return optional<U>();
55+
I tail = ranges::prev(ranges::next(first, std::move(last)));
56+
return optional<U>(in_place, ranges::fold_right(std::move(first), tail, iter_value_t<I>(*tail), std::move(f)));
57+
```
58+
* decay_t[link /reference/type_traits/decay.md]
59+
* invoke_result_t[link /reference/type_traits/invoke_result.md]
60+
* iter_reference_t[link /reference/iterator/iter_reference_t.md]
61+
* prev[link /reference/iterator/ranges_prev.md]
62+
* invoke[link /reference/functional/invoke.md]
63+
* optional[link /reference/optional/optional.md]
64+
* fold_right[link ./ranges_fold_right.md]
65+
* iter_value_t[link /reference/iterator/iter_value_t.md]
66+
67+
空の入力範囲に対しては無効値を保持する[`optional`](/reference/optional/optional.md)を返す。
68+
69+
## 計算量
70+
71+
入力範囲`r``[first, last)`)の要素数を`N`とすると、正確に`N - 1`回の`f`の適用が行われる。
72+
73+
## 備考
74+
75+
この関数の戻り値型は[`optional`](/reference/optional/optional.md)`<U>`であり、`U`は次のように求められる型と一致する
76+
77+
```cpp
78+
auto tail = --last;
79+
decltype(ranges::fold_right(std::move(first), tail, iter_value_t<I>(*tail), f));
80+
```
81+
* fold_right[link ./ranges_fold_right.md]
82+
* iter_value_t[link /reference/iterator/iter_value_t.md]
83+
84+
すなわち、他の引数はそのままに初期値として入力範囲`r`の要素を手動で指定して`fold_right`を呼び出した際の戻り値型を包む`optional`となる。
85+
86+
`fold_right`と同様に、この型`U`は`fold_right_last`の処理内部で積算値の型として使用されるものでもあり、`f`は`*first`の代わりに`U`の右辺値も受け取れる必要がある。詳細は下の実装例を参照。
87+
88+
## 例
89+
90+
### 基本的な数値集計処理の例
91+
92+
```cpp example
93+
#include <ranges>
94+
#include <algorithm>
95+
#include <functional>
96+
#include <print>
97+
#include <vector>
98+
99+
using namespace std::ranges;
100+
101+
int main() {
102+
// 入力
103+
range auto rng = views::iota(1, 11);
104+
// 二項演算
105+
auto op = std::plus<>{};
106+
107+
auto resl = fold_right_last(rng, op);
108+
109+
std::println("{:d}", resl.value());
110+
111+
112+
// 入力範囲はfloatのvector
113+
std::vector<float> rngf = { 0.125f, 0.25f, 0.75f };
114+
115+
// 計算結果はoptional<float>
116+
auto reslf = fold_right_last(rngf, op);
117+
118+
std::println("{:g}", reslf.value());
119+
}
120+
```
121+
* fold_right_last[color ff0000]
122+
* iota[link /reference/ranges/iota_view.md]
123+
* plus[link /reference/functional/plus.md]
124+
* println[link /reference/print/println.md]
125+
126+
### 出力
127+
```
128+
55
129+
1.125
130+
```
131+
132+
### 空の入力範囲に対する動作の例
133+
134+
```cpp example
135+
#include <ranges>
136+
#include <algorithm>
137+
#include <functional>
138+
#include <print>
139+
#include <vector>
140+
141+
using namespace std::ranges;
142+
143+
int main() {
144+
range auto rng = views::empty<int>;
145+
auto op = std::plus<>{};
146+
147+
auto res1 = fold_left(rng, -1, op);
148+
auto res2 = fold_right_last(rng, op);
149+
150+
std::println("{:d}", res1);
151+
std::println("{:d}", res2.value_or(-1));
152+
}
153+
```
154+
* fold_right_last[color ff0000]
155+
* fold_left[link ranges_fold_right.md]
156+
* println[link /reference/print/println.md]
157+
* value_or[link /reference/optional/optional/value_or.md]
158+
159+
### 出力
160+
```
161+
-1
162+
-1
163+
```
164+
165+
## 実装例
166+
167+
```cpp
168+
template<bidirectional_iterator I, sentinel_for<I> S,
169+
indirectly-binary-right-foldable<iter_value_t<I>, I> F>
170+
requires constructible_from<iter_value_t<I>, iter_reference_t<I>>
171+
constexpr auto fold_right_last(I first, S last, F f) {
172+
using U = decay_t<invoke_result_t<F&, iter_reference_t<I>, T>>;
173+
174+
if (first == last) {
175+
return optional<U>();
176+
}
177+
178+
I tail = ranges::prev(ranges::next(first, std::move(last)));
179+
180+
if (first == tail) {
181+
return optional<U>(in_place, *tail);
182+
}
183+
184+
const auto copy_tail = tail;
185+
U accum = invoke(f, *--tail, *copy_tail);
186+
187+
while (first != tail) {
188+
accum = invoke(f, *--tail, std::move(accum));
189+
}
190+
191+
return optional<U>(in_place, std::move(accum));
192+
}
193+
```
194+
195+
## バージョン
196+
### 言語
197+
- C++23
198+
199+
### 処理系
200+
- [Clang](/implementation.md#clang): ??
201+
- [GCC](/implementation.md#gcc): 13.1
202+
- [Visual C++](/implementation.md#visual_cpp): 2022 Update 5
203+
204+
## 関連項目
205+
206+
- [`ranges::fold_left`](ranges_fold_left.md)
207+
- 範囲の左からの`fold`
208+
- [`ranges::fold_right`](ranges_fold_right.md)
209+
- 範囲の右からの`fold`
210+
- [`ranges::fold_left_first`](ranges_fold_left_first.md)
211+
- 範囲の最後の要素を初期値として`fold_right`
212+
- [`ranges::fold_left_with_iter`](ranges_fold_left_with_iter.md.nolink)
213+
- `fold_left`の結果と共に、計算した終端イテレータも返す
214+
- [`ranges::fold_left_first_with_iter`](ranges_fold_left_first_with_iter.md.nolink)
215+
- `fold_left_first`の結果と共に、計算した終端イテレータも返す
216+
217+
## 参照
218+
219+
- [P2322R6 `ranges::fold`](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2322r6.html)

0 commit comments

Comments
 (0)