2014-04-29 8 views
6

मैं यह सुनिश्चित करना चाहता हूं कि एक व्युत्पन्न वर्ग एक विशिष्ट स्थैतिक विधि लागू करता है। मुझे लगता है कि ऐसा करना संभव है static_assert, std::is_same, decltype, CRTP और शायद SFINAE का उपयोग करना संभव है। हालांकि, similar code मैंने पाया कि अब तक काफी जटिल है और ऐसा लगता है कि मैं अभी तक पूरी तरह से समझ नहीं पा रहा हूं कि यह मुझे अपनी आवश्यकताओं को अपनाने में असमर्थ है।व्युत्पन्न कक्षा लागू करें स्थिर विधि

मैं अब तक क्या करने की कोशिश की इस

template <class T> 
class Base 
{ 
    static_assert(std::is_same<decltype(T::foo(1)), int>::value, "ERROR STRING"); 
}; 

class Derived : public Base <Derived> 
{ 
public: 
    static int foo(int i) { return 42; }; 
}; 

हालांकि, यह मुझे बता संकलन नहीं है कोई एक तत्व foo भले ही विधि सही ढंग से लागू किया गया है नामित है कि व्युत्पन्न है। इसके अलावा static_assert के अंदर अभिव्यक्ति में foo के लिए वास्तविक पैरामीटर प्रदान करना गलत लगता है।

खोज एसओ ने एक समान प्रश्न का खुलासा किया जो अंत में मुझे this piece of code पर ले जाता है जहां यह जांच की जाती है कि एक प्रकार के तरीके() और अंत() को पुनरावर्तक करने वाले हैं। तो मैंने अपनी जरूरतों को इस कोड को अपनाने की कोशिश की।

template <class T> 
class Base 
{ 
    template<typename C> 
    static char(&g(typename std::enable_if<std::is_same<decltype(static_cast<int(C::*)(int)>(&C::foo)), int(C::*)(int)>::value, void>::type*))[1]; 

    template<typename C> 
    static char(&g(...))[2]; 

    static_assert(sizeof(g<T>(0)) == 1, "ERROR STRING"); 
}; 

लेकिन यह कोड संकलित नहीं करता है क्योंकि दावा आग लगती है।

तो मेरे सवालों का

  1. क्यों संकलक व्युत्पन्न :: मेरी पहली उदाहरण में foo नहीं मिल सकता है कर रहे हैं?
  2. उदाहरण कोड में typename C::const_iterator(C::*)() const क्या है? क्या यह एक कॉन्स फ़ंक्शन नहीं है जो C :: const_iterator लौटा रहा है और कोई तर्क नहीं ले रहा है? C::* का वास्तव में क्या मतलब है? तो int(C::*)(int) क्यों है तो मेरे मामले में गलत?
  3. मेरी समस्या का सही ढंग से समाधान कैसे करें?

मैं एमएसवीसी 12 का उपयोग कर रहा हूं लेकिन यदि संभव हो तो कोड पोर्टेबल होना चाहिए।

+1

आप एक पार्सर नहीं हैं, अपने कोड को टोकननाइज़ न करें! :) टेम्पलेट्स पहले से पढ़ने के लिए काफी मुश्किल हैं; * बहुत * लाइनों में एक रेखा को विभाजित करना इससे भी बदतर हो जाता है। – Rubens

+1

'" त्रुटि STRING "' दावा विफलता के लिए संदेश की एक खराब पसंद है। सही विकल्प है ["जैबरवॉकी उपयोगकर्ता को मार रहा है।"] (Http://stackoverflow.com/questions/21553327/why-is-except-pass-a-bad-programming-practice/21553515#21553515) – Casey

+0

आधार के रूप में और व्युत्पन्न खराब वर्ग के नाम हैं और foo एक खराब विधि नाम है। ;) लेकिन यह एसएससीसीई के रूप में था और मैंने स्ट्रिंग को महत्वपूर्ण नहीं माना। हालांकि, "त्रुटि STRING" का उद्देश्य यह बताना था कि कुछ वास्तविक त्रुटि स्ट्रिंग है। मैंने कुछ चुना है जैसे "टी हस्ताक्षर के साथ एक विधि को लागू करने की जरूरत है ..."। लेकिन वैसे भी टिप्पणी के लिए धन्यवाद। :) – sigy

उत्तर

12

यह एक आम समस्या CRTP का उपयोग करते समय है: Base<Derived> बिंदु जहां यह Derived के ठिकानों की सूची में आती है पर instantiated है, जिस पर समय Derived के बाद से इसकी घोषणा के बाकी नहीं है नहीं अभी तक पूरी तरह से प्रकार है अभी तक पार्स किया गया है। विभिन्न कामकाज हैं। static_assert के लिए, आपको Derived पूरा होने तक दावा के तत्कालता में देरी की आवश्यकता है।

template <class T> 
class Base 
{ 
public: 
    ~Base() { 
     static_assert(std::is_same<decltype(T::foo(1)), int>::value, "ERROR STRING"); 
    } 
}; 

class Derived : public Base<Derived> 
{ 
public: 
    static int foo(int) { return 42; }; 
}; 

प्रश्न # 2 को संबोधित करते: C::* वाक्य रचना है - एक तरह से ऐसा करने के लिए Base कि आप जानते हैं instantiated किया जाना चाहिए के एक सदस्य समारोह में जोर डालने के लिए है नाशक हमेशा एक अच्छा विकल्प (Live at Coliru) है "C वर्ग के सदस्य के लिए सूचक।" तो int(*)(int) "समारोह के लिए एक एकल int पैरामीटर लेने और int लौटने के लिए सूचक" है, और int(C::*)(int) तुलनात्मक रूप से है "C के सदस्य समारोह एक भी int पैरामीटर लेने और int लौटने के लिए सूचक।" कुरूपता

typename C::const_iterator(C::*)() const 

"C की लगातार सदस्य कार्य करने के लिए सूचक कोई पैरामीटर लेने और C::const_iterator लौटने" के लिए अनुवाद होगा जहां के पाठ्यक्रम typename संकेत मिलता है कि निर्भर नाम C::const_iterator एक प्रकार है आवश्यक है।

+0

बेशक! मैं एक ही गलती में बार-बार क्यों दौड़ूं? मुझे यह इंगित करने के लिए धन्यवाद (दोबारा);) हालांकि, यह अभी भी foo():/ – sigy

+1

@sigy के लिए वास्तविक पैरामीटर प्रदान करने के लिए अजीब लगता है यदि यह वास्तव में आपको परेशान करता है, तो आप 'std :: declval' का उपयोग कर सकते हैं एक "जेनेरिक" पूर्णांक रैवल्यू अभिव्यक्ति: 'static_assert (std :: is_same ())), int> :: value," ERROR STRING ");'। आप 'is_convertible ' 'is_same' के बजाय भी विचार कर सकते हैं। – Casey

+0

फिर से धन्यवाद। जब तक सभी सवालों से निपटने का कोई जवाब नहीं है, मैं आपका जवाब स्वीकार करूंगा। यह मेरी समस्या हल करता है। – sigy

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