2015-11-17 12 views
12

निम्नलिखित पर विचार करें:खाका उर्फ ​​दृश्यता नेस्टेड वर्ग में

template<typename X> 
struct Z {}; 

struct A 
{ 
    using Z = ::Z<int>; 

    struct B : Z 
    { 
     using C = Z; 
    }; 
}; 

यह ठीक संकलित करता है। अच्छा लगा। लेकिन अब Z में दूसरा पैरामीटर जोड़ें:

template<typename X, typename Y> 
struct Z {}; 

struct A 
{ 
    template<typename X> 
    using Z = ::Z<X, int>; 

    struct B : Z<B> 
    { 
     using C = Z<B>; // error: too few template arguments for class template 'Z' 
    }; 
}; 

ठीक है, शायद यह भावना है कि वर्ग A में टेम्पलेट उर्फ ​​Z की परिभाषा दिखाई जब नेस्टेड वर्ग B पाने है बनाता है, लेकिन इसके शरीर के अंदर नहीं है, क्योंकि त्रुटि ट्रिगर Z की वैश्विक परिभाषा में दो पैरामीटर हैं।

लेकिन क्यों व्यवहार पहले मामले में अलग है, जब ZA में सिर्फ एक प्रकार उर्फ ​​है?

template<typename X, typename Y> 
struct Z {}; 

template<typename T> 
struct A 
{ 
    template<typename X> 
    using Z = ::Z<X, int>; 

    struct B : Z<B> 
    { 
     using C = Z<B>; 
    }; 
}; 

अब त्रुटि चला गया है:

अंत में, A एक टेम्पलेट बनाते हैं। क्यों?

(बजना 3.6 और जीसीसी 4.9.2 पर परीक्षण किया गया)

उत्तर

9

संक्षेप में: Z की विशेषज्ञता से पाने इंजेक्शन-वर्ग-नाम ::Z की, जो उर्फ ​​टेम्पलेट से पहले पाया जाता है प्रस्तुत करता है। यदि A एक टेम्पलेट है, हालांकि, इंजेक्शन-क्लास-नाम अब और नहीं मिला है क्योंकि B का बेस क्लास निर्भर है।


[temp.local]/1 पर विचार करें:

सामान्य (गैर- टेम्पलेट) वर्गों की तरह, वर्ग टेम्पलेट्स एक इंजेक्शन-वर्ग-नाम (धारा 9) है। इंजेक्शन-वर्ग-नाम एक टेम्पलेट नाम या एक प्रकार- नाम रूप इस्तेमाल किया जा सकता।

और [basic.lookup]/3:

इंजेक्शन-वर्ग-नाम एक वर्ग के (धारा 9) भी उद्देश्यों के लिए है कि वर्ग के एक सदस्य माना जाता है नाम [...] लुकअप

Z एक अयोग्य नाम के रूप में देखा जाता है; [Basic.lookup.unqual]/7:

enter image description here

इस प्रकार, इंजेक्शन-वर्ग-नामZ आधार वर्ग Z<B, int> के सदस्य के रूप में पाया जाता है, और एक टेम्पलेट नाम रूप में इस्तेमाल किया , जो आपके दूसरे कार्यक्रम को खराब बना देता है।वास्तव में, अपने पहले स्निपेट के रूप में अच्छी तरह से इंजेक्शन-वर्ग-नाम उपयोग करता है - निम्नलिखित स्निपेट संकलन नहीं होगा:

struct A 
{ 
    using Z = ::Z<float>; 
    struct B : ::Z<int> 
    { 
     static_assert(std::is_same<Z, ::Z<float>>{}, ""); 
    }; 
}; 

अंत में, यदि A एक टेम्पलेट बना है, ध्यान दें कि B एक आश्रित प्रकार के रूप में है प्रति [temp.dep.type]/(9.3) , इस प्रकार Z<B> [temp.dep.type]/(9.7) के अनुसार एक निर्भर प्रकार है, इस प्रकार बेस क्लास Z<B> की जांच के लिए लुकअप के दौरान नहीं की जाती है unqualified-idZ [temp.dep]/3:

के अनुसार

के एक वर्ग परिभाषा में [..], एक निर्भर आधार वर्ग (14.6.2.1) के दायरे से या तो वर्ग टेम्पलेट या सदस्य की परिभाषा के बिंदु पर अयोग्य नाम देखने के दौरान जांच नहीं कर रहा है या कक्षा टेम्पलेट या सदस्य के तत्काल के दौरान।

इसलिए इंजेक्शन-क्लास-नाम नहीं मिलेगा।


B, एक "नेस्टेड वर्ग [..] एक निर्भर सदस्य वर्तमान इन्स्टेन्शियशन की है कि" (जोर मेरा) है

के बाद से एक नाम एक निर्भर है वर्तमान तात्कालिकता के सदस्य यदि वर्तमान तात्कालिकता के सदस्य हैं, तो जब देखा जाता है, तो उस वर्ग के कम से कम एक सदस्य को संदर्भित करता है जो वर्तमान तत्काल है।

+0

वाह। यह काफी स्पष्ट है, धन्यवाद। वास्तव में त्रुटि तब दिखाई दी जब 'ए' एक टेम्पलेट होने से रोका, जिसे मैंने सोचा था कि कोड को बहुत सरल बना देगा। हालांकि, अब मुझे दो 'जेड' के लिए दो अलग-अलग नामों का उपयोग करने के लिए मजबूर किया गया है, जो केवल कोड को उलझन में डाल देता है। यदि कोई बेहतर कामकाज है, तो कृपया मुझे बताएं। – iavr

+0

@iavr 'सी = जेड का उपयोग करने के बारे में क्या;'? अपने मूल एक ('अज्ञात प्रकार का नाम 'Z'') पर :-) हाँ, यह यहाँ इस सरलीकृत कोड पर काम करता है – Columbo

+0

अब जब कि प्रभावशाली है (के लिए' A' एक टेम्पलेट जा रहा है काम नहीं करेगा), लेकिन नहीं। मुझे यह जांचना होगा कि अंतर कहां है। 'ए 'अब एक टेम्पलेट नहीं है, और मैं इसे इस तरह से रखना चाहता हूं। – iavr

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