क्लैंग द्वारा typename
की जांच करने के लिए परीक्षण करते समय मैं इस अजीब व्यवहार में भाग गया। एमएसवीसी ने इसे खारिज करते हुए दोनों क्लैंग और जीसीसी इस कोड को स्वीकार करते हैं।क्या टाइपनाम को लाइन सदस्य परिभाषा के बाहर-विनिर्देशक में छोड़ा जा सकता है?
template<class T1>
struct A
{
template<class T2>
struct B
{
static B f;
static typename A<T2>::template B<T1> g;
};
};
template<class T1>
template<class T2>
typename A<T2>::template B<T1> // ok, typename/template required
A<T1>::B<T2>::g;
template<class T1>
template<class T2>
A<T1>::B<T2> // clang/gcc accept, msvc rejects missing typename
A<T1>::B<T2>::f;
सामान्य तौर पर, एक योग्य-आईडी A<T1>::B<T2>
(जहां A<T1>
एक आश्रित नाम है) typename A<T1>::template B<T2>
लिखा जाना चाहिए। क्या जीसीसी/क्लैंग का व्यवहार गलत है, या क्या इस विशेष मामले में सामान्य नियम (नीचे उद्धृत) का अपवाद है?
यह तर्क दिया जा सकता है कि A<T1>
एक आश्रित नाम नहीं है, या B<T2>
वर्तमान तत्कालता के सदस्य को संदर्भित करता है। हालांकि, प्रकार-विनिर्देशक को पार्स करने के बिंदु पर यह जानना संभव नहीं है कि वर्तमान तत्कालता A<T1>
है। यह अनुमान लगाने के लिए समस्याग्रस्त लगता है कि A<T1>
वर्तमान तात्कालिकता है।
14,6 नाम संकल्प [temp.res]
एक टेम्पलेट घोषणा या परिभाषा में इस्तेमाल एक नाम और है कि एक टेम्पलेट पैरामीटर पर निर्भर जब तक लागू नाम देखने पाता है एक प्रकार नाम नहीं मान लिया है कीवर्ड टाइपनाम द्वारा एक प्रकार का नाम या नाम योग्य है। टेम्पलेट विशेषज्ञता के
14.2 नाम [temp.names]
जब एक सदस्य टेम्पलेट विशेषज्ञता का नाम प्रदर्शित होता
.
या->
एक पोस्टफ़िक्स अभिव्यक्ति में या एक एक योग्य-आईडी में नेस्टेड-नाम-विनिर्देशक के बाद के बाद , और पोस्टफिक्स-अभिव्यक्ति की ऑब्जेक्ट या पॉइंटर अभिव्यक्ति या योग्य-आईडी में नेस्टेड-नाम-विनिर्देशक टेम्पलेट पैरामीटर (14.6.2) पर निर्भर करता है लेकिन वर्तमान तत्कालता (14.6) के सदस्य का संदर्भ नहीं देता है। 2.1), सदस्य टेम्पलेट नाम को कीवर्ड टेम्पलेट द्वारा उपसर्ग किया जाना चाहिए। अन्यथा नाम गैर-टेम्पलेट का नाम माना जाता है।
आगे की जांच करने के लिए क्या बजना यहाँ क्या कर रहा है, मैं भी कोशिश की इस:
template<class T1>
struct C
{
template<class T2>
struct D
{
static typename A<T1>::template B<T2> f;
static typename A<T1>::template B<T2> g;
};
};
template<class T1>
template<class T2>
typename A<T1>::template B<T2> // ok, typename/template required
C<T1>::D<T2>::f;
template<class T1>
template<class T2>
A<T1>::B<T2> // clang rejects with incorrect error
C<T1>::D<T2>::g;
बजना error: redefinition of 'g' with a different type
देता है, लेकिन g
के प्रकार वास्तव में घोषणा से मेल खाता है।
मैं इसके बजाय typename
या template
के उपयोग का सुझाव देने वाले निदान को देखने की अपेक्षा करता हूं।
यह इस परिकल्पना को श्रेय देता है कि पहले उदाहरण में क्लैंग का व्यवहार अनपेक्षित है।
मैं व्यक्तिगत रूप से जोड़ना होगा 'typename' ... लेकिन नहीं है मानक में अभी खोदने के लिए ड्राइव :) –
@dribeas कोई चिंता नहीं;)। अब तक आप इन सभी भाषा वकील प्रश्नों से थक गए होंगे! – willj
चाहे वह सही या गलत है, आप किसी भी * कोड * जीसी और क्लैंग स्वीकार करने के लिए सिर्फ एक अपवर्तनीय के लायक हैं, लेकिन वीसी ++ लापता 'टाइपनाम 'के आधार पर अस्वीकार कर देता है। –