2010-04-07 33 views
61

C++ 0x thêm hash<...>(...).Làm cách nào để kết hợp các giá trị băm trong C++ 0x?

Tôi không thể tìm thấy hàm băm_combine, như được trình bày trong boost. Cách sạch nhất để thực hiện một cái gì đó như thế này là gì? Có lẽ, sử dụng C++ 0x xor_combine?

+0

Có thể trùng lặp của [Làm thế nào để chuyên std :: hash cho người dùng định nghĩa các loại?] (Https://stackoverflow.com/questions/24361884/how-to-specialize-stdhasht-for-user-defined-types) – Raedwald

+0

Một chuyên môn của 'std :: hash' vốn đã kết hợp sub h tro của các thành viên dữ liệu. Tất cả các bằng chứng và lý luận áp dụng có áp dụng cho một hàm 'hash_combine'. – Raedwald

+0

@Raedwald Tôi thấy bây giờ đó là một trong những câu hỏi phụ của ông, nhưng để công bằng, câu hỏi của ông là periphrastic và gián tiếp. Thêm câu trả lời của bạn ở đây nếu bạn có gì đó để thêm. –

Trả lời

63

Vâng, chỉ cần làm điều đó như những kẻ tăng đã làm nó:

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); 
} 
+15

vâng, đó là điều tốt nhất tôi có thể làm. Tôi không hiểu làm thế nào ủy ban tiêu chuẩn từ chối một cái gì đó rất rõ ràng. –

+8

@Neil: Tôi đồng ý. Tôi nghĩ rằng một giải pháp đơn giản cho họ sẽ là yêu cầu của thư viện để có một băm cho 'std :: pair' (hoặc' tuple', thậm chí). Nó sẽ tính toán giá trị băm của từng phần tử, sau đó kết hợp chúng. (Và theo tinh thần của thư viện chuẩn, trong một cách thực hiện được xác định.) – GManNickG

+3

Có rất nhiều điều hiển nhiên bị bỏ qua khỏi tiêu chuẩn. Quá trình đánh giá ngang hàng chuyên sâu làm cho việc đưa những thứ nhỏ bé ra khỏi cửa trở nên khó khăn. – stinky472

20

tôi sẽ chia sẻ nó ở đây vì nó có thể hữu ích cho những người khác tìm kiếm giải pháp này: bắt đầu từ @KarlvonMoor câu trả lời, đây là một mẫu phiên bản variadic, đó là terser trong sử dụng của nó nếu bạn cần phải kết hợp nhiều giá trị với nhau:

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...); 
} 

Cách sử dụng:

std::size_t h=0; 
hash_combine(h, obj1, obj2, obj3); 

này được viết ban đầu để thực hiện một macro variadic để dễ dàng thực hiện các loại tùy chỉnh hashable (mà tôi nghĩ là một trong những tập quán chính của một hàm 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;\ 
      }\ 
     };\ 
    } 

Cách sử dụng:

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ác vấn đề liên quan