C++0x が追加されますhash<...>(...)
。
boosthash_combine
に示されているように、関数が見つかりませんでした。このようなものを実装する最もクリーンな方法は何ですか? おそらく、 C++0x を使用していますか?xor_combine
まあ、ブースト担当者がやったようにやってください:
template <class T>
inline void hash_combine(std::size_t& seed, const T& v)
{
std::hash<T> hasher;
seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
}
このソリューションを探している他の人に役立つ可能性があるため、ここで共有します。@KarlvonMoorの回答から始めて、ここに可変引数テンプレートバージョンがあります。複数の値を組み合わせる必要がある場合、使用方法が簡潔です。
inline void hash_combine(std::size_t& seed) { }
template <typename T, typename... Rest>
inline void hash_combine(std::size_t& seed, const T& v, Rest... rest) {
std::hash<T> hasher;
seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
hash_combine(seed, rest...);
}
使用法:
std::size_t h=0;
hash_combine(h, obj1, obj2, obj3);
これは元々、可変引数マクロを実装してカスタム型を簡単にハッシュ可能にするために作成されました (これは関数の主な用途の 1 つだと思いhash_combine
ます)。
#define MAKE_HASHABLE(type, ...) \
namespace std {\
template<> struct hash<type> {\
std::size_t operator()(const type &t) const {\
std::size_t ret = 0;\
hash_combine(ret, __VA_ARGS__);\
return ret;\
}\
};\
}
使用法:
struct SomeHashKey {
std::string key1;
std::string key2;
bool key3;
};
MAKE_HASHABLE(SomeHashKey, t.key1, t.key2, t.key3)
// now you can use SomeHashKey as key of an std::unordered_map
数日前、この回答のわずかに改善されたバージョンを思いつきました(C++ 17 のサポートが必要です)。
template <typename T, typename... Rest>
void hashCombine(uint& seed, const T& v, Rest... rest)
{
seed ^= ::qHash(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
(hashCombine(seed, rest), ...);
}
コード生成に関しては、上記のコードの方が優れています。コードで Qt の qHash 関数を使用しましたが、他のハッシュ関数を使用することもできます。
vt4a2hによる回答は確かに素晴らしいものですが、C++17 の折り畳み式を使用しているため、誰もが簡単に新しいツールチェーンに切り替えることができるわけではありません。以下のバージョンは、エキスパンダー トリックを使用してフォールド式をエミュレートし、C++11およびC++14でも機能します。
さらに、関数をマークinline
し、可変個引数のテンプレート引数に完全転送を使用します。
template <typename T, typename... Rest>
inline void hashCombine(std::size_t &seed, T const &v, Rest &&... rest) {
std::hash<T> hasher;
seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
(int[]){0, (hashCombine(seed, std::forward<Rest>(rest)), 0)...};
}