2012-03-10 17 views
9

मैं अपने ऑब्जेक्ट के लिए हैश फ़ंक्शन लिख रहा हूं। मैं पहले से ही हैश कंटेनर कर सकता हूं, और हैश को जोड़ सकता हूं, Generic Hash function for all STL-containers के लिए धन्यवाद। लेकिन मेरे वर्गों में भी enums है। बेशक मैं हर enum के लिए एक हैश समारोह बना सकते हैं, लेकिन यह एक अच्छा विचार प्रतीत नहीं होता है। क्या std::hash के लिए कुछ सामान्य विनिर्देश बनाना संभव है, ताकि यह हर enum पर लागू किया जा सके? ऐसा ही कुछ, का उपयोग कर std::enable_if और std::is_enumसी ++ 11 हैश फ़ंक्शन किसी भी एनम प्रकार

namespace std { 
    template <class E> 
    class hash<typename std::enable_if<std::is_enum<E>::value, E>::type> { 
    public: 
    size_t operator()(const E& e) const { 
     return std::hash<std::underlying_type<E>::type>()(e); 
    } 
    }; 
}; 

पी एस। इस कोड को संकलित नहीं है

error: template parameters not used in partial specialization: 
error:   ‘E’ 

उत्तर

4

यह संभव है, द्वारा

अन्यथा, एक ही रास्ता मैं करने के लिए आसानी से हैश enum मान पाया है हैश प्रकार सामान्यीकरण करने के लिए है टेम्पलेट तर्क सूची से विशेषज्ञता विफलता को स्थानांतरित करना ताकि ई की पैरामीटर कटौती अभी भी हो। उदाहरण के लिए, आप इसे एक का उपयोग कर घोषणा पर पाए जाते हैं हो सकता है: (। मैं आमतौर पर प्रकार का नाम sfinae उपयोग करती हैं इसलिए मुझे याद है कि वह वहाँ क्यों है)

namespace std { 
    template<class E>class hash { 
    using sfinae = typename std::enable_if<std::is_enum<E>::value, E>::type; 
    public: 
    size_t operator()(const E&e) const { 
     return std::hash<typename std::underlying_type<E>::type>()(e); 
    } 
    }; 
}; 

डेमो कोड:

#include <functional> 

namespace std { 
    template<class E>class hash { 
    using sfinae = typename std::enable_if<std::is_enum<E>::value, E>::type; 
    public: 
    size_t operator()(const E&e) const { 
     return std::hash<typename std::underlying_type<E>::type>()(e); 
    } 
    }; 
}; 

enum foo { BAR, BAZ }; 
class quux {}; 

int main() { 
    // Compiles. 
    std::hash<foo>foo_hash; 
    // Gives a compile-time error: no type named ‘type’ in ‘struct 
    // std::enable_if<false, quux>’. 
    std::hash<quux>quux_hash; 
    return 0; 
} 
+0

यह 'टेम्पलेट कक्षा हैश 'प्राथमिक टेम्पलेट' हैश' को परिभाषित करता है, विशेषज्ञता नहीं। एक विशेषज्ञता इस तरह दिखेगी: 'टेम्पलेट कक्षा हैश >'। मुझे सच में नहीं लगता कि आप प्राथमिक टेम्पलेट 'std :: हैश ' को फिर से परिभाषित कर सकते हैं। – cdyson37

+0

@ cdyson37 इसके अलावा, जो भी आप उल्लेख करते हैं वह _partial विशेषज्ञताकरण पूर्ण प्रतीत होता है 'टेम्पलेट <> स्ट्रक्चर हैश {...}; '** इसके अलावा **, आंशिक विशेषज्ञता मानक के खिलाफ है और इसे निर्दिष्ट किया गया है ** अपरिभाषित व्यवहार **। इसे देखें [SO प्रश्न/उत्तर] (http://stackoverflow.com/questions/28077592/extending-namespace-std-via-partial-template- विशेषज्ञता)। –

+1

यह वास्तव में आंशिक विशेषज्ञता है। लेकिन मेरा मानना ​​है कि इसकी अनुमति है - देखें [यहां] (http://stackoverflow.com/questions/23339298/stdhash-template-partial-specialization) – cdyson37

10

आपका E पैरामीटर, निष्कर्ष निकाला नहीं जा सकता क्योंकि संकलक है कि आपके enable_if<...>::typeE फिर से दर्शाने समाप्त होता है (और वास्तव में, वहाँ इसके बारे में कुछ विशेषज्ञताओं है कि डिजाइन तक ऐसा नहीं करते हैं पता नहीं कर सकते हैं उस!)। इसे E के लिए "गैर-कटौती संदर्भ" कहा जाता है।

यदि hash में केवल एक पैरामीटर है, तो आपके आंशिक विशेषज्ञता से SFINAE को कोई रास्ता नहीं है (जिसे मैं जानता हूं)।

4

यदि आप मैक्रोज़ का उपयोग करने के इच्छुक हैं, तो आप अपनी enum घोषणा के बगल में सही std :: हैश विशेषज्ञता को डंप कर सकते हैं।

struct enum_hash 
{ 
    template <typename T> 
    inline 
    typename std::enable_if<std::is_enum<T>::value, std::size_t>::type 
    operator()(T const value) const 
    { 
     return static_cast<std::size_t>(value); 
    } 
}; 

और इसे उस तरह से उपयोग करते हुए:

enum class E { a, b, c }; 
std::unordered_map<E, std:string, enum_hash> map; 
map[E::a] = "a"; 
2

जो आप करने की कोशिश कर रहे हैं वह मानक द्वारा निषिद्ध है।

[namespace.std]

एक सी के व्यवहार ++ कार्यक्रम unde फाई नेड अगर यह नाम स्थान एसटीडी भीतर एसटीडी या एक नाम स्थान के लिए नाम स्थान के लिए जब तक अन्यथा निर्दिष्ट घोषणाओं या डी फाई nitions जोड़ता है।

एक कार्यक्रम किसी भी मानक पुस्तकालय टेम्पलेट एसटीडी नाम स्थान के लिए केवल तभी घोषणा एक उपयोगकर्ता के डी फाई नेड प्रकार पर निर्भर करता है और विशेषज्ञता मूल टेम्पलेट के लिए मानक पुस्तकालय आवश्यकताओं को पूरा करती है और एक टेम्पलेट विशेषज्ञता जोड़ सकते हैं नहीं स्पष्ट है निषिद्ध।

तो आप निश्चित रूप से इन उत्तरों में कुछ विचारों का पीछा कर सकते हैं, लेकिन आप इसे std :: हैश नहीं कह सकते हैं। अपने स्वयं के 'enum_hash' टेम्पलेट को परिभाषित करना एक अच्छा विचार है।

संबंधित मुद्दे