Skip to content

Commit

Permalink
functional/hash: 説明増補
Browse files Browse the repository at this point in the history
  • Loading branch information
yohhoy committed Feb 21, 2023
1 parent 9755c4c commit 496bf9c
Showing 1 changed file with 30 additions and 11 deletions.
41 changes: 30 additions & 11 deletions reference/functional/hash.md
Expand Up @@ -36,9 +36,11 @@ namespace std {
## 概要
クラステンプレート`hash`は、非順序連想コンテナ([`unordered_map`](/reference/unordered_map/unordered_map.md)/[`unordered_multimap`](/reference/unordered_map/unordered_multimap.md)/[`unordered_set`](/reference/unordered_set/unordered_set.md)/[`unordered_multiset`](/reference/unordered_set/unordered_multiset.md))のキーとなる型のためのハッシュ値を計算する関数オブジェクトである。
このクラスはそのものにデフォルトの定義は存在せず、ユーザーが任意の型で特殊化する際の要件を定義する。`hash`クラステンプレートを特殊化する場合、以下に記述するメンバ関数を持たせる必要がある
このクラスはそのものにデフォルトの定義は存在せず、ユーザーが任意の型で特殊化する際の要件を定義する。`hash`クラステンプレートを特殊化する場合、後述するメンバ関数を持たせる必要がある
`<functional>`ヘッダでは、以下の特殊化を提供する。これ以外の特殊化は、対象型を定義する各種ヘッダファイルにて提供される:
### 基本型のハッシュサポート
`<functional>`ヘッダでは、基本型に対する特殊化を提供する。
`std::string`などC++標準ライブラリ定義の型に対する特殊化は、対象型を定義する各種ヘッダファイルにて提供される。
| 型 | 対応バージョン |
|----------------------|----------------|
Expand Down Expand Up @@ -69,18 +71,25 @@ namespace std {
## メンバ関数
| 名前 | 説明 |
|-----------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------|
| `hash()`<br/>`hash(const hash&)`<br/>`hash(hash&&)` | デフォルトコンストラクタ、コピーコンストラクタ、ムーブコンストラクタを持つ |
| `~hash()` | デストラクタを持つ |
| `hash& operator=(const hash&)`<br/>`hash& operator=(hash&&)` | コピー代入演算子とムーブ代入演算子を持つ |
| `size_t operator()(T key) const` | 関数呼び出し演算子によって、キーに対応するハッシュ値を返す |
|------|------|
| `(constructor)` | デフォルトコンストラクタ、コピーコンストラクタ、ムーブコンストラクタを持つ |
| `(destructor)` | デストラクタを持つ |
| `operator=` | コピー代入演算子とムーブ代入演算子を持つ |
| `operator()` | 関数呼び出し演算子によって、キー値`k`に対応する`size_t`型のハッシュ値を返す。`const`修飾メンバ関数。 |
関数呼び出し演算子に関する制約は次の通り :
- 引数に指定するキー値`k`を変更してはならない。
- ハッシュ計算は引数で指定したキー値以外に依存してはいけない(状態をもってはいけない)。
- 式`k1 == k2`を満たす2個のキー値に対しては、同一ハッシュ値を返すこと。
- 異なる2個のキーに対して同一ハッシュ値を返すこと(collision; 衝突)は許容されるが、入力に対する出力ハッシュ値は`size_t`型の値域において均等分布することが好ましい。
## メンバ型
| 名前 | 説明 | 対応バージョン |
|------|------|----------------|
| `is_transparent` | 省略可。ハッシュ計算の関数オブジェクトがこの型を持っている場合、非順序連想コンテナの透過的な検索関数が有効になる。<br/>この型は、例として`hash<string>`が`hash<const char*>`や`hash<string_view>`と等価なハッシュ値を生成できるような場合に定義される。 | C++20 |
| `is_transparent` | 省略可。ハッシュ計算を行う関数オブジェクトがこの型を持っている場合、非順序連想コンテナの透過的な検索関数が有効になる。<br/>この型は、例えば関数オブジェクトが`string`型/`string_view`型/ヌル終端文字列(`const char*`)に対して等価なハッシュ値を生成できる場合に定義される。 | C++20 |
## 例
Expand All @@ -89,6 +98,8 @@ namespace std {
#include <iostream>
#include <functional>
enum class E { A = 1, B = 42, C = 100 };
int main()
{
int x;
Expand All @@ -104,6 +115,10 @@ int main()
// int*型のアドレス値(&x)に対するハッシュ値を求める
std::cout << std::hash<int*>()(&x) << std::endl;
// 列挙型の値E::Bに対するハッシュ値を求める(C++14から)
E e = E::B;
std::cout << std::hash<E>()(e) << std::endl;
}
```
* std::hash[color ff0000]
Expand All @@ -114,10 +129,11 @@ int main()
100
1427109137
3219530756
42
```

### 透過的にハッシュ値を計算できる場合 (C++20)
`is_transparent`が定義される場合、以下のようなコードにおいて、`find()`メンバ関数に文字列リテラルを指定しても、一時的な[`string`](/reference/string/basic_string.md)オブジェクトが作成されず、パフォーマンス向上が期待できる。
メンバ型`is_transparent`が定義される場合、以下のようなコードにおいて、[`find`](/reference/unordered_map/unordered_map/find.md)メンバ関数に文字列リテラルを指定しても、一時的な[`string`](/reference/string/basic_string.md)オブジェクトが作成されず、パフォーマンス向上が期待できる。

```cpp example
#include <iostream>
Expand All @@ -135,14 +151,15 @@ struct string_hash {

int main()
{
// キー型=std::string, 値型=int
std::unordered_map<std::string, int, string_hash, std::equal_to<>> um = {
{"Alice", 3},
{"Bob", 1},
{"Carol", 4}
};

// string_hashおよびstd::equal_to<>はいずれもメンバ型にis_transparentを持つため、
// find()などの検索関数に引数を渡す場合に、std::string一時オブジェクトが作られない
// find()などの検索関数に値を渡す場合に、キー型(std::string)一時オブジェクトが作られない
auto it = um.find("Alice");
if (it != um.end()) {
std::cout << "found : " << it->second << std::endl;
Expand Down Expand Up @@ -189,7 +206,9 @@ found : 3
## 参照
- [ハッシュ関数 - Wikipedia](https://ja.wikipedia.org/wiki/ハッシュ関数)
- [LWG 2148 - Hashing enums should be supported directly by std::hash](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2148)
- [LWG 2148 - Hashing enums should be supported directly by `std::hash`](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2148)
- [LWG 2291 - std::hash is vulnerable to collision DoS attack](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2291)
- [LWG 2543 - LWG 2148 (hash support for enum types) seems under-specified](https://cplusplus.github.io/LWG/issue2543)
- [LWG 2817 - `std::hash` for `nullptr_t`](https://cplusplus.github.io/LWG/issue2817)
- [P0919R3 Heterogeneous lookup for unordered containers](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0919r3.html)
- [P1690R1 Refinement Proposal for P0919 Heterogeneous lookup for unordered containers](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1690r1.html)

0 comments on commit 496bf9c

Please sign in to comment.