Skip to content

Commit 6688b15

Browse files
committed
reflection : ハッシュ値計算の例を追加
1 parent 9d2eae5 commit 6688b15

1 file changed

Lines changed: 68 additions & 0 deletions

File tree

lang/cpp26/reflection.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,74 @@ int main() {
416416
```
417417
418418
419+
### 任意の型のハッシュ値を自動で求める
420+
リフレクションを使うことで、任意のクラス型に対する汎用的なハッシュ関数を実装できる。以下の例では以下の方針で実装する:
421+
422+
- [`std::hash`](/reference/functional/hash.md)`<T>`が特殊化されていればそれを使う
423+
- 特殊化されていない場合は、クラスのすべての非静的データメンバに対して再帰的にハッシュ値を計算しXORで合成する
424+
425+
これにより、ネストしたクラス型に対しても自動的にハッシュ値を計算できる。
426+
427+
```cpp example
428+
#include <meta>
429+
#include <functional>
430+
#include <string>
431+
#include <print>
432+
433+
// std::hash<T>が使用可能かを判定するコンセプト
434+
template <class T>
435+
concept has_std_hash = requires(const T& x) {
436+
{ std::hash<T>{}(x) } -> std::convertible_to<std::size_t>;
437+
};
438+
439+
template <class T>
440+
constexpr std::size_t hash_value(const T& obj) {
441+
if constexpr (has_std_hash<T>) {
442+
// std::hashが特殊化されていれば利用する
443+
return std::hash<T>{}(obj);
444+
} else {
445+
// 特殊化されていなければ、各メンバのハッシュ値を再帰的に計算してXORで合成
446+
std::size_t result = 0;
447+
template for (constexpr auto m :
448+
std::define_static_array(std::meta::nonstatic_data_members_of(^^T,
449+
std::meta::access_context::unchecked()))) {
450+
result ^= hash_value(obj.[:m:]);
451+
}
452+
return result;
453+
}
454+
}
455+
456+
struct Inner {
457+
int a;
458+
std::string b;
459+
};
460+
461+
struct Outer {
462+
int x;
463+
Inner inner; // ネストしたクラス型も再帰的にハッシュ化される
464+
};
465+
466+
int main() {
467+
Outer o1{10, {1, "hello"}};
468+
Outer o2{10, {1, "hello"}};
469+
Outer o3{10, {2, "hello"}};
470+
471+
std::println("hash(o1) == hash(o2): {}", hash_value(o1) == hash_value(o2));
472+
std::println("hash(o1) == hash(o3): {}", hash_value(o1) == hash_value(o3));
473+
}
474+
```
475+
* std::hash[link /reference/functional/hash.md]
476+
* std::convertible_to[link /reference/concepts/convertible_to.md]
477+
* std::meta::nonstatic_data_members_of[link /reference/meta/nonstatic_data_members_of.md]
478+
* std::meta::access_context::unchecked[link /reference/meta/access_context/unchecked.md]
479+
480+
#### 出力
481+
```
482+
hash(o1) == hash(o2): true
483+
hash(o1) == hash(o3): false
484+
```
485+
486+
419487
## <a id="relative-page" href="#relative-page">関連項目</a>
420488
- [`<meta>`ヘッダ](/reference/meta.md)
421489
- [C++26 コンパイル時のタプルやリストを展開処理する`template for`](/lang/cpp26/expansion_statements.md)

0 commit comments

Comments
 (0)