2011-10-25 5 views
7

इस कोड के बाद:variadic टेम्पलेट्स - अधूरा प्रकार

template<class ...Args> 
struct Are_Same 
{ 
    enum {value = Are_Same<Args...>::value}; 
}; 

template<class A,class... C> 
struct Are_Same<A,C...> 
{ 
    enum {value = Are_Same<A,C...>::value};//HERE is THE ERROREOUS LINE 
}; 

template<class A,class B> 
struct Are_Same<A,B> 
{ 
    enum {value = std::is_same<A,B>::value}; 
}; 

मैं जीसीसी 4.6.1 से त्रुटि मिल रही है:

error: incomplete type 'Are_Same' used in nested name specifier.

मैंने सोचा था कि Are_Same<A,C...>::value करके मैं पुनरावर्ती कॉल लागू करेगा, जिस पर अंत बस Are_Same<A,B> तक विस्तारित होगा। जाहिर है यह मामला नहीं है। कोई जानता है कि मैं गलती कहां कर रहा हूं?

उत्तर

8

मुझे लगता है कि टेम्पलेट की परिभाषा गलत है, दोनों मामलों में आप सटीक रिकर्सन ट्रिगर कर रहे हैं। मैं संकलक संकलक लेकिन एक अलग त्रुटि का उत्पादन किया है अंदर कुछ stackoverflow के साथ मरने के लिए ...

are_same variadic टेम्पलेट का एक कार्यान्वयन हो सकता है की उम्मीद है |:

template <class... Args>     // base (optional to declare the template) 
struct are_same; 

template <class A, class B, class... Args> // recursion 
struct are_same<A,B,Args...> { 
    static const bool value = is_same<A,B>::value && are_same<A,Args...>::value; 
}; 

template <class A, class B>     // stop condition 
struct are_same<A,B> { 
    static const bool value = is_same<A,B>::value; 
}; 

ध्यान दें कि recursion चरण में , तर्कों की सूची से एक तर्क गिरा दिया जाता है, ताकि हल करने की नई समस्या मूल के संस्करण को कम कर दे। इस प्रकार का टेम्पलेट मेटाप्रोग्रामिंग रिकर्सन से काफी संबंधित है, और उसी नियम लागू होते हैं, ताकि आप यह सुनिश्चित करने के लिए रिकर्सन का उपयोग कर सकें कि प्रत्येक रिकर्सिव चरण आपको समाधान के करीब ले जाता है। इस विशेष मामले में, एन संभावित रूप से समान प्रकार की एक सूची दी गई है, प्रत्येक चरण समस्या को कम करता है यह पता लगाने के लिए कि क्या एन -1 प्रकार समान हैं।

आप वैकल्पिक रूप से, are_same समस्या का एक पतित संस्करण (पूर्व एक की जगह) का उपयोग कर सकते रोक शर्त के रूप में:

template <class A> 
struct are_same<A> { 
    static const bool value = true; 
}; 

कौन सा अर्थ में पतित कि यह वास्तव में भावना है कि क्या पूछ नहीं है है एक प्रकार * are_same *, लेकिन विभिन्न मेटाप्रोग्रामिंग कार्यों के लिए यह उचित हो सकता है।

एक अलग संभवतः अधिक कुशल एल्गोरिथ्म (मुझे यकीन है कि है कि क्या संकलक ऊपर प्रत्यावर्तन कदम में टेम्पलेट के इन्स्टेन्शियशन से बचने जाएगा नहीं कर रहा हूँ) है कि is_same पर निर्भर नहीं करता हो सकता है:

template <class... Args> 
struct are_same; 

template <class A, class... Args> 
struct are_same<A,A,Args...> {    // recursion 
    static const bool value = are_same<A,Args...>::value; 
}; 

template <class A, class B, class... Args> 
struct are_same<A,B,Args...> {    // cut, A and B are not the same 
    static const bool value = false; 
}; 

template <class A> 
struct are_same<A> {      // end of recursion 
    static const bool value = true; 
}; 

इस मामले में , जब भी दो प्रकार समान होते हैं, तो संकलक recursioncut चरणों में पसंद करेंगे, इसलिए हमें आंतरिक रूप से is_same जांचने की आवश्यकता नहीं है। साथ ही, यदि कंपाइलर cut चरण में जाता है, तो हमें बाकी प्रकार की सूची को संसाधित करने की आवश्यकता नहीं है, क्योंकि हम पहले ही जवाब जानते हैं।

+1

जो शानदार शानदार है, खासकर "शॉर्ट सर्किट" चरण। धन्यवाद। – smallB

+0

अच्छा, लेकिन पहले कोड स्निपेट में एक छोटी सी बग है। 'स्थिर कॉन्स बूल वैल्यू = is_same :: value && are_same :: मान;' –

+1

@VJo: एक बार यह साबित हो गया है कि 'ए == बी', '' या' 'कोई फर्क नहीं पड़ता, न ही इसका कोई फायदा होगा, आप टेम्पलेट का एक नया तात्कालिकता शुरू कर रहे हैं और इस बिंदु पर संकलक' ए' और 'बी' के प्रकार के लिए हल करेगा (यानी 'int ',' डबल' ...), कोड के दोनों टुकड़े बिल्कुल वही हैं। –

3

मैं इस तरह यह करना होगा:

#include <type_traits> 
#include <iostream> 

template <class... Args> 
struct are_same 
{ 
    static const bool value=true; 
}; 

template <class A, class B, class... Args> // recursion 
struct are_same<A,B,Args...> { 
    static const bool value = std::is_same<A,B>::value && are_same<B,Args...>::value; 
}; 

int main() 
{ 
    std::cout<< std::boolalpha << are_same<int>::value << std::endl; 
    std::cout<< std::boolalpha << are_same< int, int, int >::value << std::endl; 
    std::cout<< std::boolalpha << are_same< int, int, double, int >::value << std::endl; 
} 
+0

धन्यवाद मुझे स्थिति को रोकने के बिना रास्ता पसंद है। उत्तम सामग्री; +1 – smallB

+2

@smallB: इसमें बिल्कुल वही स्टॉप हालत है, यह सिर्फ सामान्य टेम्पलेट में छिपा हुआ है, केवल दो विशेषज्ञ हैं, एक सामान्य चरण के लिए, एक स्टॉप हालत के लिए एक (इस मामले में स्टॉप स्थिति * अधिक दिखती है सामान्य * के रूप में यह 'टेम्पलेट <वर्ग ... Args>' है, लेकिन यह केवल कंपाइलर के लिए सबसे अच्छा मिलान होगा जब यह अब 'रिकर्सन' चरण (यानी जब एक प्रकार का होता है) लागू नहीं कर सकता है तो मेरे मामले में I स्टॉप हालत को और अधिक स्पष्ट करना पसंद करते हैं क्योंकि मुझे लगता है कि मुझे लगता है कि कैसे/कब रिकर्सन रुक जाएगा, लेकिन यह सिर्फ वरीयता है। –

0

शायद सबसे सरल कार्यान्वयन इस तरह हो सकता है:

template <typename... TList> 
struct are_same { constexpr static bool value = false; }; 

template <typename T, typename... TList> 
struct are_same<T, T, TList...> { 
    constexpr static bool value = are_same<T, TList...>::value; 
}; 

template <typename T> 
struct are_same<T> { constexpr static bool value = true; }; 

वैकल्पिक रूप से आप

template <typename T> 
struct are_same<T, T> { constexpr static bool value = true; }; 

लेकिन पहले के साथ बंद हालत की जगह ले सकता एक अधिक सामान्य है क्योंकि are_same<type>::value == true। एक और सवाल यह है कि are_same<>::value के बराबर होना चाहिए। यह आपको false देता है लेकिन इस तरह एक और टेम्पलेट विशेषज्ञता जोड़ने के लिए यह एक बड़ा सौदा नहीं है।

template <> 
struct are_same<> { constexpr static bool value = true; };