2012-11-24 14 views
5

मैं एक टेम्पलेट वर्ग (प्राप्त < नामित> यहाँ) को लागू करने की कोशिश कर रहा हूँ कि एक संरचना एच दिया, प्रकार Get<H>::typeH ही अगर qualified-idH::der मौजूद नहीं है, और Get<H::der>::type अन्यथा है । मैं समझ नहीं पा रहा हूं कि निम्नलिखित कोड में क्या गड़बड़ है:C++ पुनरावर्ती प्रकार लक्षण

#include <iostream> 
#include <typeinfo> 
using namespace std; 

template<class U, class V = void> 
struct Get 
{ 
    static const char id = 'A'; 
    typedef U type; 
}; 

template<class U> 
struct Get<U,typename U::der> 
{ 
    static const char id = 'B'; 
    typedef typename Get<typename U::der>::type type; 
}; 

struct H1 
{ }; 
struct H2 
{ typedef double der; }; 
struct H3 
{ typedef void der; }; 
struct H4 
{ typedef H2 der; }; 

void print(char id, const char* name) 
{ 
    cout << id << ", " << name << endl; 
} 
int main(int , char *[]) 
{ 
    print(Get<H1>::id, typeid(Get<H1>::type).name()); // prints "A, 2H1", OK 
    print(Get<H2>::id, typeid(Get<H2>::type).name()); // prints "A, 2H2", why? 
    print(Get<H3>::id, typeid(Get<H3>::type).name()); // prints "B, v" , OK 
    print(Get<H4>::id, typeid(Get<H4>::type).name()); // prints "A, 2H4", why? 
} 

मुझे इस कोड को अपेक्षित व्यवहार करने में कुछ मदद चाहिए। विशेष रूप से, मैं चाहता हूँ कि < एच 2 प्राप्त करें> :: प्रकार बराबर डबल करने के लिए लिए किया गया था, और एक ही < एच 4 प्राप्त करें> :: प्रकार

+0

संभव डुप्लिकेट http://stackoverflow.com/questions/3008571/template-specialization-to-use -default-type-if-class-member-typedef-does-not-exi) –

+2

इस उत्तर में litb की 'tovoid' चाल आपकी समस्या हल करती है: http://stackoverflow.com/a/3009891/245265 –

+0

अच्छी चाल, हेवन यह नहीं जानता था। – ipc

उत्तर

2

जब मैं जवाब @ipc पर +1 देने के लिए और यह बहुत अच्छी तरह से सी ++ 11 सक्षम compilers के लिए है, सी ++ 03 compilers के लिए आप एक अलग दृष्टिकोण का उपयोग करना चाहिए, क्योंकि फ़ंक्शन के टेम्पलेट तर्कों के लिए डिफ़ॉल्ट मान C++ 03 में समर्थित नहीं है। तो मैं इस कोड है:

template<class U, class V = void> 
struct Get 
{ 
    static const char id = 'A'; 
    typedef U type; 
}; 

template< class T > 
struct is_type { 
    static const bool value = true; 
}; 

template<class U> 
struct Get<U, 
    typename std::tr1::enable_if<is_type<typename U::der>::value, void>::type> 
{ 
    static const char id = 'B'; 
    typedef typename Get<typename U::der>::type type; 
}; 
[अगर वर्ग के सदस्य typedef मौजूद नहीं है डिफ़ॉल्ट प्रकार का उपयोग करने के खाका विशेषज्ञता] (की
+0

यदि आप 'boost :: enable_if' (' std :: enable_if' सी ++ 11 का उपयोग कर रहे हैं) का उपयोग कर रहे हैं, 'टाइपनाम नाम :: enable_if :: type' भी काम करना चाहिए और' is_type बनाता है 'सहायक वर्ग अधूरा। – ipc

+0

@ipc असल में मैं अपने असली प्रोजेक्ट में 'boost :: enable_if' का उपयोग कर रहा हूं लेकिन ऐसा नहीं है, क्योंकि' boost :: enable_if' की स्थिति 'mpl' बूलियन स्थिर होना चाहिए। सही कोड 'boost :: enable_if > 'है। और कृपया याद रखें कि 'std :: enable_if'' TR1' से संबंधित है C++ 11 नहीं। – BigBoss

+0

ठीक है, आप सही हैं। लेकिन 'std :: enable_if' अभी भी सी ++ 11 है क्योंकि' std' में 'std :: tr1' एम्बेड करना गैर मानक है। – ipc

2

टेम्पलेट Get<> में एक डिफ़ॉल्ट टेम्पलेट पैरामीटर है - यह बहुत खतरनाक है। V के आधार पर int, void या double के आधार पर आपको अलग-अलग परिणाम मिलते हैं। यह होता है:

Get<H2>::type पहले स्थान पर (id='A' के साथ) है। अब चेक आता है, चाहे इसका कोई विशेषज्ञता हो। आपका बी Get<U,typename U::der> है जो Get<U, double> बन जाता है। लेकिन यह Get<H2, void> के साथ मेल नहीं खाता है, इसलिए A चुना गया है। चीजें Get<H2>::type के साथ दिलचस्प हो रही हैं। फिर संस्करण बी Get<U, void> भी है और एक बेहतर मैच प्रदान करता है। हालांकि, दृष्टिकोण सभी प्रकार के लिए काम नहीं कर सकता है।

यह मैं Get कैसे लागू कर दिया है होता है:

template<class U> 
class Get 
{ 
    template <typename T, typename = typename T::der> 
    static typename Get<typename T::der>::type test(int); 
    template <typename T> 
    static T test(...); 
public: 
    typedef decltype(test<U>(0)) type; 
};