C ++ 0x에서 해시 값을 어떻게 결합합니까?
C ++ 0x는 hash<...>(...).
hash_combine하지만 boost에 제시된 기능을 찾을 수 없습니다 . 이와 같은 것을 구현하는 가장 깨끗한 방법은 무엇입니까? 아마도 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);
이것은 원래 사용자 정의 유형을 쉽게 해시 할 수 있도록 가변 매크로를 구현하기 위해 작성되었습니다 (내가 생각하기에 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
이는 다음과 같이 가변 템플릿을 사용하여 해결할 수도 있습니다.
#include <functional>
template <typename...> struct hash;
template<typename T>
struct hash<T>
: public std::hash<T>
{
using std::hash<T>::hash;
};
template <typename T, typename... Rest>
struct hash<T, Rest...>
{
inline std::size_t operator()(const T& v, const Rest&... rest) {
std::size_t seed = hash<Rest...>{}(rest...);
seed ^= hash<T>{}(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
return seed;
}
};
용법:
#include <string>
int main(int,char**)
{
hash<int, float, double, std::string> hasher;
std::size_t h = hasher(1, 0.2f, 2.0, "Hello World!");
}
One could certainly make a template function, but this could cause some nasty type deduction e.g hash("Hallo World!") will calculate a hash value on the pointer rather than on the string. This is probably the reason, why the standard uses a struct.
A few days ago I came up with slightly improved version of this answer (C++ 17 support is required):
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), ...);
}
The code above is better in terms of code generation. I used qHash function from Qt in my code, but it's also possible to use any other hashers.
I really like the C++17 approach from the answer by vt4a2h, however it suffers from a problem: The Rest is passed on by value whereas it would be more desirable to pass them on by const references (which is a must if it shall be usable with move-only types).
Here is the adapted version which still uses a fold expression (which is the reason why it requires C++17 or above) and uses std::hash (instead of the Qt hash function):
template <typename T, typename... Rest>
void hash_combine(std::size_t& seed, const T& v, const Rest&... rest)
{
seed ^= std::hash<T>{}(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
(hash_combine(seed, rest), ...);
}
For completeness sake: All the types which shall be usable with this version of hash_combine must have a template specialization for hash injected into the std namespace.
Example:
namespace std // Inject hash for B into std::
{
template<> struct hash<B>
{
std::size_t operator()(B const& b) const noexcept
{
std::size_t h = 0;
cgb::hash_combine(h, b.firstMember, b.secondMember, b.andSoOn);
return h;
}
};
}
So that type B in the example above is also usable within another type A, like the following usage example shows:
struct A
{
std::string mString;
int mInt;
B mB;
B* mPointer;
}
namespace std // Inject hash for A into std::
{
template<> struct hash<A>
{
std::size_t operator()(A const& a) const noexcept
{
std::size_t h = 0;
cgb::hash_combine(h,
a.mString,
a.mInt,
a.mB, // calls the template specialization from above for B
a.mPointer // does not call the template specialization but one for pointers from the standard template library
);
return h;
}
};
}
참고URL : https://stackoverflow.com/questions/2590677/how-do-i-combine-hash-values-in-c0x
'Program Club' 카테고리의 다른 글
| 상속 : 'A'는 'B'의 액세스 할 수없는 기반입니다. (0) | 2020.10.14 |
|---|---|
| OpenID Connect에서 ID 토큰 만료 시간의 의도는 무엇입니까? (0) | 2020.10.14 |
| Java에서 이벤트 리스너와 핸들러의 차이점은 무엇입니까? (0) | 2020.10.14 |
| C 프로그램에서 100 % CPU 사용량을 얻는 방법 (0) | 2020.10.14 |
| 표준 입력에서 읽기 위해 sed를 어떻게 얻습니까? (0) | 2020.10.14 |