2012-05-05 14 views
5

में नेस्टेड क्लास के लिए std :: हैश को विशेषज्ञता देना मेरे पास एक टेम्पलेट क्लास Baz है जिसमें एक नेस्टेड क्लास Sub है। मैं std :: हैश विशेषज्ञता के द्वारा इस सबक्लास के लिए हैश फ़ंक्शन को परिभाषित करना चाहता हूं। हालांकि, यह काम नहीं लग रहा है।एक टेम्प्लेट क्लास

#include <functional> 

struct Foo { 
    struct Sub { 
    }; 
}; 

template <class T> 
struct Bar { 
}; 

template <class T> 
struct Baz { 
    struct Sub { 
     int x; 
    }; 
}; 

// declare hash for Foo::Sub - all right 
namespace std { 
    template <> 
    struct hash<Foo::Sub>; 
} 

// declare hash for Bar<T> - all right 
namespace std { 
    template <class T> 
    struct hash< Bar<T> >; 
} 

// declare hash function for Baz<T>::Sub - doesn't work! 
namespace std { 
    template <class T> 
    struct hash< Baz<T>::Sub >; 
} 

// Adding typename produces a different error. 
namespace std { 
    template <class T> 
    struct hash< typename Baz<T>::Sub >; 
} 

जीसीसी 4.5.3 शिकायत:

$ g++ -std=c++0x -c hash.cpp 
hash.cpp:34:30: error: type/value mismatch at argument 1 in template parameter list for ‘template<class _Tp> struct std::hash’ 
hash.cpp:34:30: error: expected a type, got ‘Baz<T>::Sub’ 
hash.cpp:40:12: error: template parameters not used in partial specialization: 
hash.cpp:40:12: error:   ‘T’ 

अद्यतन

क्या मैं सच में ऐसा करने की कोशिश कर रहा हूँ एक कंटेनर जो स्थिर संदर्भ (सी में नहीं का समर्थन करता है को लागू ++ है भावना) इसके भीतर तत्वों के लिए। मैं उपयोगकर्ता को इन संदर्भों को std::unordered_set और इसी तरह से सम्मिलित करने की अनुमति देना चाहता हूं, और मौजूदा तत्वों को कुशलतापूर्वक एक्सेस या संशोधित करने के लिए उनका उपयोग करें। निम्नलिखित सिर्फ एक नकली है, सटीक कंटेनर नहीं जिसे मैं कार्यान्वित कर रहा हूं। समस्या संदर्भ प्रकार के लिए हैश फ़ंक्शन को परिभाषित करने में है।

template <class T> 
class Container { 
public: 
    class Reference { 
    public: 
     // operator==, operator!=, operator< ...., isNull() 
    private: 
     size_t index; // index into m_entries (or could be anything else) 
     // possibly more stuff 
    }; 

    Reference insert (const T &value); 
    Reference find (const T &value); 
    void remove (Reference r); 
    Reference first(); 
    Reference next (Reference prev); 

private: 
    struct Entry { T value, ... }; 

    std::vector<Entry> m_entries; 
}; 
+0

इस के लिए USECASE क्या है? शायद आपके कंटेनर के लिए एक स्पष्ट हैश फ़ंक्शन निर्दिष्ट करना आसान होगा? –

उत्तर

2

इस प्रश्न का उत्तर यह है कि आप जो करना चाहते हैं वह करना असंभव है। कंपाइलर यह नहीं समझ सकता कि बाहरी वर्ग में उपप्रकार क्या है।

struct outer1 { typedef int Sub; }; 
struct outer2 { typedef int Sub; }; 

कैसे संकलक जो बाहरी आप जब यह एक उप हो जाता है चाहता हूँ यह पता लगाने की माना जाता है: क्यों विचार करें? यह नहीं कर सकते। काम करने के लिए कोई संभावित तरीका नहीं है।

आपके मामले में यह दूरस्थ रूप से संभव हो सकता है, हालांकि आईएफएफ सब को टी पर निर्भर करता है, लेकिन यह संकलक को यह जानने की आवश्यकता होगी कि सब कहाँ से आता है और यह नहीं करता है।

तो आप बस यह नहीं कर सकते हैं। कोई रास्ता नहीं, कैसे नहीं।

यदि आपको अपने प्रकार के लिए हैश फ़ंक्शन खोजने के लिए कुछ सामान्य दृष्टिकोण की आवश्यकता है तो आपको मेटाफंक्शन get_hash बनाना होगा। यह डिफ़ॉल्ट रूप से "हैश_टाइप" आंतरिक टाइपपीफ की तलाश कर सकता है और मानक हैश के लिए ओवरराइड किया जा सकता है। बहुत सारे टाइपिंग ...

वैकल्पिक रूप से, युक्त वर्ग के उप-आउट को अपने स्वयं के टेम्पलेट के रूप में रखें और आंतरिक कक्षा के बजाय वहां टाइप टाइप करें। फिर आप अपने टेम्पलेट पर हैश विशेषज्ञ कर सकते हैं।

अन्यथा, केवल उस हैश की आपूर्ति करें जिसे आप जानते हैं कि आपको उस टेम्पलेट में हैश फ़ंक्शन पैरामीटर की आवश्यकता है जिसे आप उपयोग कर रहे हैं।

+0

हां, आप सही हैं; इस उदाहरण में, जब संकलक को 'int' मिलता है, तो यह नहीं पता कि किस हैश का उपयोग करना है। हालांकि, मेरे उदाहरण में, मैं टाइपिफ़ का उपयोग नहीं करता, लेकिन एक नेस्टेड क्लास, जो कि किसी और चीज के लिए उपनाम नहीं है; जब संकलक उप हो जाता है, तो यह पहले से ही (मुझे विश्वास है) जानता है कि यह कौन सा मूल वर्ग है। –

+0

@AmbrozBizjak - यह नहीं करता है और यह नहीं कर सकता है। आपको अपनी आंतरिक कक्षा को खींचने और इसके बजाय टाइपिफ़ का उपयोग करने की आवश्यकता है। यदि आप मुझ पर विश्वास नहीं करते हैं, तो आप दीवार के खिलाफ अपने सिर को झुकाकर बहुत समय बर्बाद कर रहे हैं ... वास्तव में। सी ++ आप जो करने की कोशिश कर रहे हैं उसका समर्थन नहीं करेगा, जिस तरह से आप इसके बारे में नहीं जा रहे हैं। मुझे लगता है कि आपको स्टैक ओवरफ्लो पर लगभग एक हजार समान प्रश्न मिलेंगे और उत्तर हमेशा एक जैसा होगा। –

+0

ठीक है, मैं देखता हूं, धन्यवाद। मैंने कक्षा को बाहर ले जाया और यह ठीक काम करता है। –

0

आप इस तरह के एक आश्रित प्रकार पर टेम्पलेट का विशेषज्ञ नहीं हो सकते हैं। मैं इस तरह कुछ कोशिश करता हूँ।

struct yes {}; 

template <typename T> 
yes accept_baz_sub(typename Baz<T>::Sub&&); 
void accept_baz_sub(...); 

template <class T> 
struct is_baz_sub : std::is_same<decltype(accept_baz_sub(std::declval<T>())), yes> 
{}; 

template <typename BazSub> 
using CheckedBazSub = typename std::enable_if<is_baz_sub<BazSub>::value, BazSub>::type; 

namespace std { 
    template <class BazSub> 
    struct hash<CheckedBazSub<BazSub>>; 
} 

संपादित करें: यह नहीं काफी काम है, [temp.alias] को §14.5.7.2 एक उपनाम टेम्पलेट का नाम कभी नहीं निष्कर्ष निकाला है अनुसार।

एक और समाधान आपके स्वयं के हैश फ़ंक्शन ऑब्जेक्ट को लिखना होगा और कंटेनर का उपयोग करने दें (उदाहरण के लिए std::unordered_map का तीसरा टेम्पलेट पैरामीटर)।

+0

"त्रुटि: आंशिक विशेषज्ञता में डिफ़ॉल्ट टेम्पलेट तर्क का उपयोग नहीं किया जा सकता है" –

4

बस संदर्भ कक्षा को कंटेनर से बाहर खींचें।

template <class Container> 
class Reference { 
public: 
    typedef typename Container::value_type value_type; // etc... 

    // operator==, operator!=, operator< ...., isNull() 
private: 
    size_t index; // index into m_entries (or could be anything else) 
    // possibly more stuff 
}; 

template <class T> 
class Container { 
public: 
    typedef ::Reference<Container> Reference; 
    friend class Reference; // If you cannot help it 

    typedef T value_type; 

    Reference insert (const T &value); 
    Reference find (const T &value); 
    void remove (Reference r); 
    Reference first(); 
    Reference next (Reference prev); 

private: 
    struct Entry { T value, ... }; 

    std::vector<Entry> m_entries; 
}; 

इस तरह विशेषज्ञ:

namespace std { 
    template <typename Container> 
    struct hash<Reference<Container>>; 
} 
+0

धन्यवाद, मैंने यही किया; हालांकि मैंने एडी के जवाब को स्वीकार किया क्योंकि उसने इसे पहले सुझाव दिया था। –

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