2013-07-07 7 views
7

मैं अनुमान लगा रहा हूं कि std::hash को ओवरलोडेड फ़ंक्शन रिज़ॉल्यूशन के दौरान किए गए निहित प्रकार रूपांतरणों से बचने के लिए टेम्पलेट स्ट्रक्चर के रूप में परिभाषित किया गया है। क्या यह कहना सही बात है?std :: हैश एक ओवरलोडेड फ़ंक्शन क्यों नहीं है?

मेरा मतलब है, मैं

std::string s; 
size_t hash = std::hash<std::string>()(s); 

के बजाय

std::string s; 
size_t hash = std::hash(s); 

लिखने के लिए पसंद करेंगे लेकिन मैं वहाँ क्यों मानक समिति दूसरा विकल्प चुना है के लिए एक कारण है अनुमान लगा रहा हूँ।

संपादित करें: निश्चित दूसरा कोड खंड।

+0

@RiaD दाएं, धन्यवाद। अचानक, यह और भी अजीब लगता है। –

उत्तर

10

यह असंभव है आंशिक रूप से फ़ंक्शन टेम्पलेट का विशेषज्ञ है, और इसलिए उपयोगकर्ता द्वारा परिभाषित टेम्पलेटेड क्लास के लिए, std::hash विशेषज्ञ होने का कोई तरीका नहीं होगा यदि यह एक फ़ंक्शन था। (आप केवल std नेमस्पेस से टेम्पलेट्स का विशेषज्ञ कर सकते हैं, लेकिन ओवरलोड नहीं कर सकते हैं, इसलिए आपके टेम्पलेटेड क्लास के उपयोगकर्ता std::unordered_map<MyClass<whatever>, MyOtherClass> नहीं बना सकते हैं, उन्हें std::unordered_map<MyClass<whatever>, MyOtherClass, ???> चुनने के लिए मजबूर किया जाएगा)। तो मज़ेदार यहां समाधान है।

namespace std 
{ 
    template<typename T> 
    struct hash<MyVector<T>> 
    { 
     size_t operator()(const MyVector<T>& v) 
     { 
      //return hash from here 
     } 
    }; 
} 

मानक पुस्तकालय के लिए वैकल्पिक तरीका कुछ SFINAE टेम्पलेट चाल का उपयोग किया जाएगा डिफ़ॉल्ट के रूप में सदस्य .hash(), और मानक हैश अन्य मामले अगर चयन करने के लिए, लेकिन ज्यादातर मामलों में आप विशेष रूप से यदि का उपयोग कर इंटरफेस पुनः स्थापित नहीं कर सकते हैं (तीसरे पक्ष के कोड)

अन्य वैकल्पिक std::swap जैसा होगा (ADL साथ चाल) करता है:

//somewhere in std::unordered_map 
using std::hash; 
size_t h = hash(key); 

मेरे अनुभव में, ADL मुश्किल है और हर कोई कोने मामलों के बारे में याद करते हैं। इसके अलावा, यहां फ़ैक्टरों का लाभ यह तथ्य है कि आप उन्हें टेम्पलेट पैरामीटर के रूप में उपयोग कर सकते हैं, ताकि आप टेम्पलेट के लिए बस एक और मज़ेदार प्लग-इन कर सकें (जैसे std::unordered_map<A, B, specialized_hash<A>>) यदि आपको लगता है कि डिफ़ॉल्ट आपके मामले के लिए गलत है।

टिप्पणियों से:

लेकिन आप std :: स्वैप बारे में कुछ और विस्तार से बता सकता है? यह अभी भी सी ++ 11 में है और इसमें उपयोगकर्ता द्वारा परिभाषित प्रकारों में कोई समस्या नहीं है, है ना? क्यों इसे लगातार बनाने के बजाय एसटीएल में कई अलग-अलग अवधारणाएं रखें?

std::hash में:

  • यह संभव है कि, उदाहरण के लिए

std::swap और std::hash के बीच एक छोटा सा फर्क है std::string कक्षा लेखक द्वारा परिभाषित हैश आपके मामले के लिए पर्याप्त नहीं होगा, यानी, यह बहुत सामान्य है, और आप अपने हैश मैप में गारंटी दे सकते हैं कि आप केवल एक ही प्रकार के तार डाल देंगे, ताकि आप हैश फ़ंक्शन प्रदान कर सकें जो तेज़ है या/और कम टकराव होने।

  • यह है:
  • वहाँ विभिन्न प्रयोजनों के लिए हैश के कई तरह तो genericity अब तक कम यहां महत्वपूर्ण है
  • ज्यादातर मामलों में यह संभव है आप एक बेहतर हैश

std::swap में बनाने के लिए कर रहे हैं संभावना नहीं है कि आप अपना स्वयं का स्वैप फ़ंक्शन चाहते हैं, लेकिन आप अभी भी इस वर्ग के लिए एक विशिष्ट का उपयोग करना चाहेंगे, न कि सामान्य std::swap जो कॉपी कन्स्ट्रक्टर कहता है।

  • ज्यादातर मामलों में एक स्वैप फ़ंक्शन बनाने के लिए आपके लिए भी संभव नहीं है, क्योंकि इसे कक्षा आंतरिक के ज्ञान की आवश्यकता होती है (उदाहरण के लिए, std::vector को निजी क्षेत्र के रूप में छिपे पॉइंटर के साथ गतिशील सरणी के रूप में कार्यान्वित किया जा सकता है, इसलिए आप नहीं होंगे उन्हें एक्सेस करने में सक्षम, अकेले उन्हें स्वैप नहीं किया गया है, और यहां तक ​​कि इस तथ्य को लागू करने वाला तथ्य भी गारंटी नहीं है)
  • केवल एक स्वैप (या होना चाहिए) है।
  • वास्तव में, वहाँ std::swap साथ एक समस्या है: मानक कंटेनर swap सदस्य समारोह, std::swap विशेष किया जा सकता है (लेकिन केवल गैर टेम्प्लेटेड वर्ग के लिए) प्रदान करते हैं और स्वैप एक नि: शुल्क समारोह है कि ADL के साथ पाया है के रूप में परिभाषित किया जा सकता है। आपको अपना स्वैप कैसे प्रदान करना चाहिए? आईएमओ जो उलझन में है, तथ्य यह नहीं कि std::swap कार्य है और std::hash एक मजेदार है।
  • एसटीएल असंगत क्यों है? मैं केवल यहां अनुमान लगा सकता हूं, लेकिन मुख्य कारण एसटीएल असंगत क्यों है (ए) बाकवर्ड संगतता और (बी) सी ++ भी काफी असंगत है।

    +0

    @ मिलिनेंबग: क्या आपके पास मानक संदर्भ है जहां यह कहता है कि आप 'std' नेमस्पेस में परिभाषित कार्यों को अधिभारित नहीं कर सकते हैं? मैंने सोचा होगा कि एडीएल आपके हैश फ़ंक्शन को पायेगा। –

    +0

    @ user1131467 '17.4.3.1/1 जब तक अन्यथा निर्दिष्ट नहीं किया जाता है, तब तक नामस्थान std के साथ नामस्थान std या नेमस्पेस को घोषणाओं या परिभाषाओं को जोड़ने के लिए सी ++ प्रोग्राम के लिए यह अपरिभाषित नहीं है।एक प्रोग्राम नामस्थान std पर किसी भी मानक पुस्तकालय टेम्पलेट के लिए टेम्पलेट विशेषज्ञता जोड़ सकते हैं। एक मानक लाइब्रेरी का ऐसा विशेषज्ञता (पूर्ण या आंशिक) परिणाम अनिर्धारित व्यवहार में होता है जब तक घोषणा बाहरी लिंक के उपयोगकर्ता द्वारा परिभाषित नाम पर निर्भर न हो और जब तक कि टेम्पलेट विशेषज्ञता मूल टेम्पलेट के लिए मानक लाइब्रेरी आवश्यकताओं को पूरा न करे। '(Http से कॉपी किया गया: //stackoverflow.com/a/109613/1012936) – milleniumbug

    +1

    निश्चित रूप से, लेकिन यदि आप अपने नामस्थान में 'हैश (माईटाइप)' को परिभाषित करते हैं, और फिर 'std :: unordered_map ' 'std के अंदर से हैश (x) 'कहा जाता है 'नेमस्पेस, फिर' std :: unordered_map 'एडीएल के कारण आपके हैश फ़ंक्शन का उपयोग करेगा (यह इसके मुख्य बिंदुओं में से एक है)। सवाल यह था कि मानक पुस्तकालय एक ओवरलोडेड फ़ंक्शन के बजाय टेम्पलेट फ़ंक्शन का उपयोग करता है जैसा कि अभी वर्णित है। –

    4

    एक संभावित कारण यह है कि इस तरह से यह अस्थिर विकल्प

    template <typrname T, typename = std::hash<T>...> 
    class unordered_set; 
    

    द्वारा डिफ़ॉल्ट के रूप में टेम्पलेट्स में इसका इस्तेमाल करने के BTW आप समारोह है कि इस तरह से

    template<typename T, typename... Args> 
    auto hasher(Args&&... args) -> whatever { 
        return std::hash<T>(std::forward<Args>(args)...)(//maybe some &'s skipped 
    } 
    

    या काम करता है बना सकते हैं (आसान है है पहचान प्रकार की अनुमति देने के लिए)

    template<typename T, typename... Args> 
    auto hasher(T t) -> whatever { 
        return std::hash<T>()(t); 
    } 
    
    +0

    'स्ट्रक्चर std :: हैशर {size_t ऑपरेटर() (टी एंड एक्स) {वापसी std :: हैश (std :: आगे (x))}}; या उस प्रभाव के लिए कुछ? समानता एक समान फैशन में की जाती है, 'ऑपरेटर ==' अधिभारित होता है और 'std :: equal_to ' डिफ़ॉल्ट रूप से) ऑपरेटर == 'को प्रतिनिधि करता है। – delnan

    +0

    यह संभव है, लेकिन मुझे नहीं लगता कि यह इतना महत्वपूर्ण है क्योंकि 'हैश' इतनी उपयोगी सुविधा नहीं है (आमतौर पर सेट जैसे डेटा संरचनाओं को केवल (सामान्य रूप से सामान्य तरीके से) की आवश्यकता होती है। विज्ञापन यदि यह इतना महत्वपूर्ण नहीं है कि हमें क्यों आवश्यकता है 1 और स्तर का संकेत। '==' (सी में): इसे 'std :: equal_to' से पहले पेश किया गया था और बराबर_to पहले से मौजूद विशेषता – RiaD

    +0

    में जोड़ा गया था जैसा ओपी दिखाया गया है, यह आपको' हैश 'को कॉल करना बहुत आसान बनाता है जब आप प्रतिस्थापन की अनुमति नहीं है। संकेतों के लिए: क्या आपने मानक लाइब्रेरी को देखा है? ;-) – delnan

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