2015-01-24 13 views
10

में लिपटे संकलित एक स्पष्ट संकलन त्रुटि के साथ इस कोड पर विचार करें,: (1)अधूरा प्रकार की नई जब टेम्पलेट

struct A; 
struct B { 
    B() { new A(); } // error: allocation of incomplete type 'A' 
}; 

का उपयोग करते हुए एक unique_ptr या तो मदद नहीं करेगा: (2)

struct A; 
struct B { 
    B() { std::make_unique<A>(); } // error: due to ~unique_ptr() 
}; 

तब (मेरे महान आश्चर्य करने के लिए) मुझे पता चला है कि इस होगा संकलन: (3)

struct A; 
struct B { 
    B() { std::make_unique<A>(); } 
}; 
struct A {}; // OK, when a definition is added **below** 

तब मैं जाँच की, कि क्या यह रूप में अच्छी तरह new साथ मदद करता है - नहीं: (4)

struct A; 
struct B { 
    B() { new A(); } // error: allocation of incomplete type 'A' 
}; 
struct A {}; 

मैं लगा यह template के साथ और वास्तव में क्या करने के लिए कुछ न कुछ है: अंदर एक templateकरताnew लपेटकर संकलन: (5)

template <typename T> 
T* my_new() { return new T(); } // OK, when wrapped in template 
struct A; 
struct B { 
    B() { my_new<A>(); } 
}; 
struct A {}; 

और बस पूर्णता के लिए के लिए, A की परिभाषा को हटाने के लिए फिर से एक त्रुटि को जन्म देती है: (6)

template <typename T> 
T* my_new() { return new T(); } // error: allocation of incomplete type 'A' 
struct A; 
struct B { 
    B() { my_new<A>(); } 
}; 
// do note: definition of A removed 

यहां क्या हो रहा है? जहां तक ​​मैं समझ गया, कंपाइलर A के आकार/परिभाषा को आवंटित करने के लिए जानना चाहिए, इस प्रकार केवल इसे घोषित करना पर्याप्त नहीं है। इसके अलावा मुझे विश्वास था कि परिभाषा आवंटन से पहले होनी चाहिए।

newसीधे (1,4) का उपयोग करते समय यह सही लगता है। लेकिन जब new लपेटा गया है, तो यह स्पष्ट है कि मैं गलत हूं (2,3,5,6)।

संभावित स्पष्टीकरण मैं अब तक पाए जाते हैं: जब तक template इन्स्टेन्शियशन होता

  • पूरा प्रकार के लिए चेक देरी हो रही है। मुझे लगता है कि यह सही है, लेकिन मेरे मामले में प्रत्यक्षnew A() का उपयोग और my_new<A>() पर कॉल वही स्थिति पर वस्तुतः होता है। तो यह कारण नहीं हो सकता है। सही?
  • अपूर्ण प्रकारों का उपयोग template के रूप में तर्क अपरिभाषित व्यवहार हो सकता है। क्या यह वास्तव में सच है? यहां तक ​​कि सभी चेतावनियों को सक्षम करते समय, संकलक शिकायत नहीं करेगा। 5 और 6 की तुलना में यह भी सुझाव मिलता है कि संकलक यह समझने के लिए पर्याप्त स्मार्ट है कि परिभाषा नीचे दी गई है (इस प्रकार वस्तुतः प्रकार को पूरा कर रहा है)।

क्यों 4 को गलत माना जाता है, जबकि 5 संकलन (या 5 केवल उग्र रूप से अपरिभाषित व्यवहार को संकलित करते हैं [लेकिन फिर 3 को भी दोषपूर्ण होना चाहिए, है ना?))?

Btw: बजना साथ ++ का परीक्षण किया - 3.5.0 और जी ++ - 4.9.2

+0

http://blog.llvm.org/2009/12/dreaded-two-phase-name-lookup.html – OmnipotentEntity

+0

यदि यह अस्पष्ट है, क्योंकि वह लेख केवल दो चरण नाम लुकअप के कठोर पक्ष को संबोधित करता है, टेम्पलेट्स नाम कोड पर एक और पास तक तत्काल नहीं किया जाता है, यह पहले से ही हो चुका है और 'ए' की परिभाषा को पढ़ता है, यही कारण है कि यह संकलित करता है। – OmnipotentEntity

+1

अनुवाद इकाई के अंत तक टेम्पलेट त्वरण में देरी करने के लिए यह एक आम कार्यान्वयन तकनीक है। आपका कोड खराब गठित है, कोई निदान आवश्यक नहीं है। –

उत्तर

6

§14.6.4.1 [अस्थायी।बिंदु]/p1,8, जोर मेरा:

1 For a function template specialization, a member function template specialization, or a specialization for a member function or static data member of a class template, if the specialization is implicitly instantiated because it is referenced from within another template specialization and the context from which it is referenced depends on a template parameter, the point of instantiation of the specialization is the point of instantiation of the enclosing specialization. Otherwise, the point of instantiation for such a specialization immediately follows the namespace scope declaration or definition that refers to the specialization.

8 A specialization for a function template, a member function template, or of a member function or static data member of a class template may have multiple points of instantiations within a translation unit, and in addition to the points of instantiation described above, for any such specialization that has a point of instantiation within the translation unit, the end of the translation unit is also considered a point of instantiation. A specialization for a class template has at most one point of instantiation within a translation unit. A specialization for any template may have points of instantiation in multiple translation units. If two different points of instantiation give a template specialization different meanings according to the one definition rule (3.2), the program is ill-formed, no diagnostic required.

B की परिभाषा के अंत में my_new<A>, एक की इन्स्टेन्शियशन के दो अंक हैं, और अनुवाद इकाई के अंत में एक रहे हैं। चूंकि उन दो बिंदुओं के परिणामस्वरूप अलग-अलग अर्थ होंगे (स्निपेट 3 और 5 के लिए), कार्यक्रम खराब गठित एनडीआर है (यानी, इसमें व्यवहार को अपरिभाषित किया गया है)।

+0

यह स्पष्ट करना चाहिए कि यह (3) और (5) जिनके अलग-अलग अर्थ हैं, (6) दोनों बिंदुओं में समान अर्थ है - इनमें से कोई भी मान्य नहीं है। सही? – Barry

+0

@ बेरी यह सही है। –

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