Skip to content

Commit

Permalink
algorithm: ヘッダ冒頭説明を区分整理
Browse files Browse the repository at this point in the history
  • Loading branch information
yohhoy committed Feb 15, 2023
1 parent 8203fdd commit d60c9f1
Showing 1 changed file with 30 additions and 12 deletions.
42 changes: 30 additions & 12 deletions reference/algorithm.md
Expand Up @@ -4,10 +4,14 @@

全てのアルゴリズムはデータ構造の実装の詳細から切り離されていて、イテレータによってパラメータ化されている。これはアルゴリズムの要件を満たすイテレータを提供しているなら、どのようなデータ構造であっても動作するということを示している。

関数オブジェクトを使用するアルゴリズムでは、`for_each``for_each_n`以外、引数として渡されたオブジェクトを書き換えてはならない。
このヘッダでは、以下の標準ヘッダをインクルードする:

- [`<initializer_list>`](initializer_list.md) (C++11)


ここでは、各アルゴリズムのテンプレートパラメータ名を、型の要件を表すために使っている。アルゴリズムを正しく利用するためには、テンプレートパラメータ名に応じたこれらの要件を満たしている必要がある。以下の通りである。
### テンプレートパラメータ名とイテレータ要件

`<algorithm>`ヘッダでは、各アルゴリズムのテンプレートパラメータ名を、型の要件を表すために使っている。アルゴリズムを正しく利用するためには、テンプレートパラメータ名に応じたこれらの要件を満たしている必要がある。以下の通りである。

| テンプレートパラメータ名 | 要件 |
|-------------------------------------------------------------------------|------------------------|
Expand All @@ -20,8 +24,6 @@
もし「効果」のセクションで、イテレータの値を書き換えるという旨の文章が書かれている場合、その引数の型は mutable iterator の要件を満たしていなければならないという追加の要件がある。
もちろん、output iterator は常に書き換え可能であるため、この追加の要件は無意味である。

いくつかのアルゴリズムは `_copy` というサフィックスが付いている。これは `_copy` サフィックスの付いていないアルゴリズムと違い、処理の結果を別のイテレータへ出力するアルゴリズムである。コピーバージョンを含めるかどうかの判断は、通常バージョンの計算量を考慮する。操作を行うコストがコピーのコストを大きく上回る場合、コピーバージョンは含めないようになっている。例えば `sort_copy` は存在しない。なぜなら、ソートのコストは大きいし、そのような場合、ユーザは `copy` してから `sort` するからだ。

テンプレートパラメータ名が `Predicate` となっている場合、`Predicate` の値 `pred` と、引数として渡すイテレータ `i` について以下の要件を満たす必要がある

- `pred(*i)``bool` として評価できなければならない。
Expand All @@ -32,30 +34,39 @@
- `binary_pred(*i1, *i2)``bool` として評価できなければならない。
- `binary_pred(*i1, *i2)` 内で `*i1``*i2` を書き変えてはならない。

関数オブジェクトを引数に取る `for_each` 以外のアルゴリズムは、その関数オブジェクトを自由にコピーしても構わない。そのため、アルゴリズムの利用者はそのことに注意する必要がある。コピーされてしまうことが問題である場合、`reference_wrapper<T>` や同様の解決手段を使ってオブジェクトの中身をコピーしないようなラッパークラスを使うといった対策を行う必要がある。
### 要素の書き換え操作
関数オブジェクトを使用するアルゴリズムでは、`for_each``for_each_n`以外、プログラム定義の関数に引数として渡された要素を書き換えてはならない。

### 関数オブジェクトの取り扱い
関数オブジェクトを引数に取る `for_each`, `for_each_n` 以外のアルゴリズムは、内部処理においてその関数オブジェクトをコピーする可能性がある。

そのため、アルゴリズムの利用者はそのことに注意する必要がある。コピーされてしまうことが問題である場合、`reference_wrapper<T>` や同様の解決手段を使ってオブジェクトの中身をコピーしないようなラッパークラスを使うといった対策を行う必要がある。

### `_copy`サフィックス付きアルゴリズム
いくつかのアルゴリズムは `_copy` というサフィックスが付いている。これは `_copy` サフィックスの付いていないアルゴリズムと違い、処理の結果を別のイテレータへ出力するアルゴリズムである。

コピーバージョンを含めるかどうかの判断は、通常バージョンの計算量を考慮する。操作を行うコストがコピーのコストを大きく上回る場合、コピーバージョンは含めないようになっている。例えば `sort_copy` は存在しない。なぜなら、ソートのコストは大きいし、そのような場合、ユーザは `copy` してから `sort` するからだ。

### イテレータ操作に関する補足
アルゴリズムの説明で `+``-` を使っているが、random-access iterator 以外のイテレータはそれを定義していない。そういった場合、 `a+n` というのは

```cpp
X tmp = a;
advance(tmp, n);
return tmp;
```
* advance[link /reference/iterator/advance.md]
を意味する。また、`b-a` は
```cpp
return distance(a, b);
```
* distance[link /reference/iterator/distance.md]

を意味する。

このヘッダでは、以下の標準ヘッダをインクルードする:

- [`<initializer_list>`](initializer_list.md) (C++11)

### 射影とRangeサポート

### 射影とRangeサポート(C++20)
C++20ではアルゴリズム関数の新しいバージョンが`std::ranges`名前空間に追加された。従来の関数と比べて以下の点が異なる:

* テンプレート引数がコンセプトによって制約される
Expand All @@ -73,6 +84,8 @@ ranges::sort(v);
// イテレータ対も渡せる
ranges::sort(v.begin(), v.end());
```
* sort[link algorithm/sort.md]
* ranges::sort[link algorithm/ranges_sort.md]
射影は、述語とは別に渡すことができる関数オブジェクトで、特定のメンバだけを対象にアルゴリズムを実行するために用いる。
Expand All @@ -88,19 +101,23 @@ vector<Person> pv = { … };
sort(pv.begin(), pv.end(), [](auto&& a, auto&& b){ return a.name < b.name; });
```
* sort[link algorithm/sort.md]

これは、述語がメンバの選択と比較という2つの仕事をしてしまっている点でよくない。この責務を分割し、メンバの選択だけを行うようにしたものが射影である。

```cpp
// デフォルトの述語({})で、nameでソート
// デフォルトの述語(ranges::less{})で、nameでソート
ranges::sort(pv, {}, [](auto&& a){ return a.name; });
// std::invokeで呼び出されるため、メンバ変数ポインタでもよい
ranges::sort(pv, {}, &Parson::name);
```
* ranges::sort[link algorithm/ranges_sort.md]
* ranges::less[link /reference/functional/ranges_less.md]
* std::invoke[link /reference/functional/invoke.md]
なお、各関数の説明においては、射影の影響は無視していることがある。
## シーケンスを変更しない操作
| 名前 | 説明 | 対応バージョン |
Expand Down Expand Up @@ -418,6 +435,7 @@ ranges::sort(pv, {}, &Parson::name);
| [`ranges::in_found_result`](algorithm/ranges_in_found_result.md) | イテレータとbool値を格納する型 | C++20 |
| [`ranges::out_value_result`](algorithm/ranges_out_value_result.md) | イテレータと値を格納する型 | C++23 |
## 関連項目
- [`<numeric>`](/reference/numeric.md)
- 数値計算のアルゴリズム
Expand Down

0 comments on commit d60c9f1

Please sign in to comment.