2013-04-10 26 views
8

मैं एक बड़ी परियोजना पर काम कर रहा हूं, जिसमें संकलित कोड का एक अनुभाग शामिल है - लेकिन मुझे समझ में नहीं आता कि कैसे। मैं इसे इस सरल उदाहरण के लिए नीचे आसुत:यह टेम्पलेट कोड संकलित क्यों करता है?

template <typename T> 
struct First { 
    typedef int type;   // (A) 
    typename T::Three order; // (B) 
}; 

template <typename T> struct Second { 
    typedef typename T::type type; 
}; 


template <typename T> struct Third { 
    int val; 
    T two; 
}; 

struct Traits { 
    typedef First<Traits> One; 
    typedef Second<One> Two; 
    typedef Third<Two> Three; 
}; 

int main(int argc, char** argv) { 
    Traits::One x; 
}; 

वर्ग First पर Traits और संदर्भ Traits::Three, टेम्प्लेट की गई है जो अपने आप में एक typedef पर Two आधारित है जो एक typedef पर First<Traits> आधारित है, ... इसलिए यह परिपत्र है । लेकिन यह कोड gcc4.6 और VC10 दोनों पर ठीक संकलित करता है। हालांकि, अगर मैं (A) और (B) चिह्नित दो पंक्तियों के क्रम को फ़्लिप करता हूं, तो कोड Second के अंदर typedef के बारे में शिकायत नहीं करता है।

यह कोड क्यों संकलित करता है, और यह क्यों है कि typedef और सदस्य परिवर्तनीय मामलों का आदेश क्यों है?

+0

कोशिश इस तरह एक पेड़ में कागज पर यह आकर्षित करने के लिए: प्रत्येक परिभाषा के लिए एक नोड बनाने, और प्रत्येक (आगे) प्रकार की घोषणा, और उसके बाद के लिए जो के लिए एक पूर्ण परिभाषा की जरूरत है और जो एक की जरूरत है किनारों आकर्षित केवल घोषणा, और आप देखेंगे कि यह परिपत्र नहीं होगा। – PlasmaHH

+0

हाय - असंबंधित, लेकिन क्या आपको पता है कि पी 0704 17 के खिलाफ एक डीआर है? –

+0

@ केरेक कोई विचार नहीं, मुझे यह भी नहीं पता कि इस तरह की चीजें कैसे तय की जाती हैं। – Barry

उत्तर

3

कहने के कुछ मूल्य हैं।

  • कोड यदि Second

    T badObject; 
    
    एक लंबी श्रृंखला "से ... instantiated" और एक "अधूरा प्रकार" त्रुटि के साथ समाप्त होने के साथ

    शामिल करने के लिए संशोधित किया गया है घेरा आप की वजह से टूट जाएगा उम्मीद है, लेकिन नहीं आप के बजाय जोड़ने

    typename T::type object; 
    

    यह आपको कह रहा है कि संकलक चतुराई से यह को देख रहा है पूरी तरह सेसंपुटित की जरूरत नहीं है, तो, केवल यह जानने के लिए कि T::type क्या है। इसे दर्शाने के लिए, ध्यान दें कि आप कानूनी तौर पर

    First { ... typedef T type; ... } 
    Second { typename T::type object; } 
    

    हो सकता है के बाद से टी कोई वर्तमान में किया जा रहा से परिभाषित वस्तुओं होता है, या

    First { ... typedef typename T::One type; ... } 
    Second { typedef typename T::type object; } 
    

    Second में typedef बाद से किसी भी वस्तुओं की एक आवृत्ति की आवश्यकता नहीं है या तो - लेकिन नहीं, कहते हैं,

    First { ... typedef typename T::One type; ... } 
    Second { typename T::type object; } 
    

    तब से केवल संकलक वास्तव में First<Traits> ऑब्जेक्ट को First<Traits> ऑब्जेक्ट में घोंसला करने की आवश्यकता है।

  • मुद्दा अदला-बदली (ए) और (बी) के साथ कि चालाक चाल संकलक ऊपर खींच लिया प्रत्येक विशेष टेम्पलेट की परिभाषा की एक नई प्रतिलिपि शुरू, यह एक समय पर एक पंक्ति को पार्स द्वारा काम कर रहा है।त्रुटि तब होती है जब First में टाइप परिभाषा तक नहीं मिली है, जब इसे Second द्वारा जानना आवश्यक है।

+1

ग्रेट धन्यवाद, यह सही है। मुझे एहसास नहीं हुआ कि संकलक एक समय में एक पंक्ति जा सकता है। – Barry

+0

मैं विनिर्देश की जाँच नहीं की है, लेकिन मुझे लगता है कि यह तभी संभव मुद्दा है। आप इसके बारे में सोचते हैं, तो आप पहले से ही पता था कि चीजों लाइन द्वारा लाइन हो - यही कारण है कि 'वर्ग एक {} है; कक्षा बी: ए; 'और 'कक्षा बी: ए; कक्षा ए {}; 'अलग हैं! – Sharkos

1

आपको typedef के लिए एक पूर्ण प्रकार की आवश्यकता नहीं है।

+0

लेकिन यह संकलित नहीं करता है: 'टेम्पलेट <टाइपनाम नामित> संरचना फ़ू { टाइपपीफ टाइपनाम नामित :: प्रकार का प्रकार; }; संरचना बार: सार्वजनिक Foo { टाइपपीफ int प्रकार; }; int मुख्य (int argc, char ** argv) { बार बी; } ' – Barry

+0

@Barry: अंतर यह है कि' 'Bar' फू ' (विरासत के कारण) और की परिभाषा की जरूरत है 'typedef' अंदर' 'Foo' Bar' का उल्लेख नहीं है, लेकिन एक नेस्टेड प्रकार के। एक नेस्टेड प्रकार एक * सदस्य * है, और संलग्न प्रकार पूरा होना चाहिए। –

1

आपने एक उत्तर स्वीकार कर लिया है जो मैंने प्रदान किए गए से कहीं बेहतर था - इसलिए मैं अपना हटा रहा हूं। हालांकि, मैंने सोचा कि आपको अपने उदाहरण में और कमी में रुचि हो सकती है। मैंने आपके मूल कोड पर वापस सहसंबंध करने के लिए ए और बी के रूप में दो पंक्तियां चिह्नित की हैं। यदि आप उन्हें फ़्लिप करते हैं, तो जैसे ही आपके उदाहरण में, संकलन विफल हो जाएगा।

template<typename T> 
struct First 
{ 
     typedef typename T::type type; 
}; 

struct Second 
{ 
     typedef int type; // (A) 
     First<Second> order; // (B) 
}; 


int main(int argc, char** argv) 
{ 
     Second x; 
}; 
संबंधित मुद्दे