2016-02-02 9 views
8

मैं आज टेम्पलेट्स के साथ खेल रहा था यह देखने के लिए कि क्या मैं कंपाइलर को बाहरी कक्षा के प्रकार को अपने आंतरिक वर्गों में से किसी एक को कम करने के लिए प्राप्त कर सकता हूं। मुझे मेरा समाधान नहीं मिला (जो मुझे संदेह है असंभव है), लेकिन एक त्रुटि को ठीक करने का प्रयास करते समय मैं बहुत अजीब व्यवहार में भाग गया कि मैं निम्नलिखित स्निपेट में कमी आई।क्या यह बेतुका कोड है जो क्लेंग और जीसीसी दोनों में एक बग ठीक करता है?

struct A 
{ 
    struct B{}; 

    template <typename T> 
    struct EverythingIsFine 
    { 
     using Outer = T; 
     using Inner = typename T::B::B::B::B::B::B; 
    }; 

    using ItWillBeOkay = EverythingIsFine<B>; // Probably not ok 
    using InnerProblem = ItWillBeOkay::Inner; // Still not ok 
    using OuterProblem = decltype(B().ItWillBeOkay::Outer::B::B::B 
            ::B::B::B::~B()); // Not even CLOSE to ok 
}; 

यह आश्चर्यजनक रूप से कोई चेतावनी के साथ संकलित करता है और क्लैंग और जीसीसी दोनों के साथ कोई त्रुटि नहीं है।
मेरे कंपाइलर के संस्करण gcc version 5.3.1 20160121 (Debian 5.3.1-7) और Debian clang version 3.6.2-3 (tags/RELEASE_362/final) (based on LLVM 3.6.2) हैं और संकलित करने के लिए उपयोग किए गए ध्वज -std=c++11 -Wall -Wextra हैं।

मैंने देखा कि यह ठीक on Ideone with the C++14 setting भी संकलित करता है।


मैं तो यह साधारण परीक्षण का इस्तेमाल किया InnerProblem और OuterProblem का सही प्रकार प्राप्त करने के लिए:

template <class T> void Type(); 
int main() 
{ 
    Type<A::InnerProblem>(); 
    Type<A::OuterProblem>(); 
} 

और जब परीक्षण संकलन दोनों compilers एक ही प्रकार की रिपोर्ट:

In function main :
main.cpp:20: undefined reference to void Type<A::B>()
main.cpp:21: undefined reference to void Type<void>()

कि कहने के लिए, InnerProblem का प्रकार A::B है और OuterProblem का प्रकार void है।


क्या यह किसी भी तरह से मानक द्वारा अनुमत है या यह दोनों कंपाइलरों में एक बग है?
और जब से मैं अपने कंपाइलर के रूप में उलझन में प्रतीत होता हूं, वास्तव में इस कोड के साथ क्या हो रहा है?

संपादित करें: सरलीकृत अनुवर्ती के रूप में, क्योंकि मुझे समझ में नहीं आता कि दो कंपाइलर एक ही परिणाम क्यों नहीं दे सकते हैं, निम्नलिखित कोड क्लैंग के साथ संकलित करता है, लेकिन जीसीसी के साथ नहीं।

struct A 
{ 
    struct B{}; 

    template <typename T> 
    struct EverythingIsFine 
    { 
     using Inner = typename T::B::B::B; 
    }; 

    using Problem = EverythingIsFine<B>::Inner::B::B::B; // Not ok 
}; 

जीसीसी अब निम्न त्रुटि आउटपुट:

main.cpp:11:26: error: 'A::B::B' names the constructor, not the type using InnerProblem = EverythingIsFine::Inner::B::B::B; // Not ok

+2

यह कोड आईसीसी और एमएसवीएस पर भी संकलित करता है – NathanOliver

+0

नया प्रश्न -> नया प्रश्न कृपया। यदि संदर्भ मदद करता है तो एक लिंक शामिल करें। –

+0

@ बाममितएगेन मुझे लगता है कि मेरा नया प्रश्न भी एक डुप्लिकेट होगा, इसलिए मैं इस बार रहूंगा, लेकिन आप सही हैं। – tux3

उत्तर

6

यह मान्य नहीं है।

The class-name is also inserted into the scope of the class itself; this is known as the injected-class-name." (9/2).

तो B::B नाम वर्ग B, B::B::B, और इतने पर करता है।

संपादित करें:

तो typename B::B नाम वर्ग B, typename B::B::B, और इतने पर करता है।

+0

यह समझ में आता है, लेकिन अगर मैं 'इनरप्रोबलेम = इटविल्लबीओके :: इनर'' को 'इनरप्रोबलेम = इटविल्ल बीओकेके :: इनर :: बी :: बी :: बी;' से बदलता हूं, तो अब जीसीसी संकलित करने में विफल रहता है और क्लैंग अभी भी ठीक संकलित करता है, क्या यह अच्छी तरह से है परिभाषित व्यवहार? जीसीसी का कहना है, "ए :: बी :: बी 'निर्माता का नाम है, न कि प्रकार"। – tux3

+0

@ tux3 - मुझे नहीं पता। मैंने आपके प्रश्न में सभी घोंसले वाले टाइपिफों का पालन नहीं किया (और नहीं करेंगे)। –

+0

@ tux3 मैंने आपके पागल घोंसले वाले नामों को या तो नहीं देखा है, लेकिन त्रुटि संदेश से निर्णय लेना, यह एक क्लैंग बग हो सकता है, http://stackoverflow.com/q/32006122/241631 – Praetorian

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