@@ -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