2014-09-25 12 views
9

मैं उलझन में हूं कि मेरा कोड त्रुटि invalid use of incomplete type क्यों नहीं बना रहा है, जबकि इस त्रुटि के बारे में मैंने जो भी पढ़ा है, उसे सुझाव दिया जाना चाहिए।
प्रश्न एक समान संरचना साथ अपने कोड का हिस्सा में प्रदर्शित (उम्मीद के रूप में) इस त्रुटि से उपजी, लेकिन मैं एक छोटा सा उदाहरण इसे पुन: पेश नहीं कर सकते हैं (कृपया के अंत में अस्वीकरण देखना सवाल)।अपूर्ण प्रकार का अमान्य उपयोग - इस मामले में कोई त्रुटि क्यों नहीं है?

मुझे क्या करना है कोशिश कर रहा हूँ का सारांश:

  • मैं एक संरचना (Tree) है, और मैं इसे करने के लिए आधार प्रकार First के विभिन्न वस्तुओं प्रदान करना चाहते हैं।
  • First की कंक्रीट कार्यान्वयन अलग वापसी मान है, तो अविवेक के दो स्तर उपयोग किया जाता है:
  • First एक सार आधार वर्ग है, और First * विभिन्न ठोस उदाहरणों को संभालने के लिए उपयोग किया जाता है।
  • template <typename Type> class TypedFirst : public First एक सार प्रकार है जो फ़ंक्शन को Type के साथ फ़ंक्शन को परिभाषित करता है।
  • अंत में ConcreteFirstXTypedFirst<Type> की ठोस विशेषज्ञता हैं।

tree.tpp में, क्यों new TF(this)नहीं करने के लिए कॉल invalid use of incomplete type त्रुटि उत्पन्न करता है? (स्थान कोड में चिह्नित है) मुझे लगता है कि त्रुटि नहीं होनी चाहिए, क्योंकि जबकि TF एक टेम्पलेट, जब मैं ConcreteFirstA उपयोग कर रहा है, tree.tpp (इसके बारे में पता यह concretefirsta.h या यहाँ तक कि first.h शामिल नहीं है नहीं है, यह केवल आगे First घोषित करता है)

इस उदाहरण के लिए पूर्ण, संकलित और चलने योग्य कोड here on pastebin पाया जा सकता है। यहां, मैं ब्रेवटी के लिए #define गार्ड और इसी तरह की चीजें बहिष्कृत करूंगा। कोड इस प्रकार है:

// tree.h 
class First; 
class Tree{ 
    public: 
    Tree() {} 
    ~Tree() {} 
    template<class TF> // where TF is a ConcreteFirst 
    void addFirstToTree(); 
    private: 
    std::map<std::string, First *> firstCollection; // <- "First"'s here 
}; 
#include "tree.tpp" 

// tree.tpp 
#include "tree.h" 

template <class TF> // where TF is a ConcreteFirst 
void Tree::addFirstToTree(){ 
    this->firstCollection[TF::name] = new TF(this); // <--- Why does this work? 
    //        ^^^^^^^^^^^^^  
} 

// first.h 
class Tree; 
class First{ 
    public: 
    static const std::string name; 
    First(const Tree *baseTree) : myTree(baseTree) {} 
    virtual ~First(); 
    protected: 
    const Tree *myTree; 
}; 

template <typename Type> class TypedFirst : public First{ 
    public: 
    static const std::string name; 
    TypedFirst(const Tree *baseTree) : First(baseTree) {} 
    Type &value() {return this->_value;} 
    private: 
    Type _value; 
}; 
#include "first.tpp" 

// first.tpp 
#include "first.h" 
template <typename Type> 
const std::string TypedFirst<Type>::name = "default typed"; 

// first.cpp 
#include "first.h" 
First::~First() {} 
const std::string First::name = "default"; 

// concretefirsta.h 
#include "first.h" 
class ConcreteFirstA : public TypedFirst<int>{ 
    public: 
    static const std::string name; 
    ConcreteFirstA(const Tree *baseTree) : TypedFirst<int>(baseTree) {} 
    ~ConcreteFirstA() {} 
}; 

// concretefirsta.cpp 
#include "concretefirsta.h" 
const std::string ConcreteFirstA::name = "firstA"; 

अंत में, कोड है कि सभी है कि एक साथ लाता है और (में) उचित फ़ंक्शन को कॉल करता है:

// main.cpp 
#include "tree.h" 
#include "first.h" 
#include "concretefirsta.h" 

int main(){ 
    Tree *myTree = new Tree(); 
    myTree->addFirstToTree<ConcreteFirstA>(); // <-- here! why is this working? 
    delete myTree; 
    return 0; 
} 

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

मेरी समस्या यह है कि मुझे इस समस्या के साथ कोड के टुकड़े में त्रुटि त्रुटि मिल रही है: लेकिन, मैं इसे एक छोटे से उदाहरण में पुन: उत्पन्न नहीं कर सकता।

इस प्रकार, मैं पूछ रहा हूँ क्यों कोड का निम्न भाग नहीं त्रुटिinvalid use of incomplete type (के रूप में मैं उम्मीद होती है) का निर्माण होता है, और मुझे आशा है कि मदद मिलेगी मुझे समझते हैं और अपने वास्तविक समस्या का समाधान।

कृपया मुझे यह न बताएं कि यह the XY problem का मामला है: मुझे पता है कि मैं अपनी वास्तविक समस्या के बारे में नहीं पूछ रहा हूं, क्योंकि मैंने (और समुदाय) ने इस प्रारूप के लिए इसे बहुत बड़ा माना है।

+0

क्या आपने संकलन त्रुटि दूर होने तक कोड को काटने का प्रयास किया है? दूसरी तकनीक प्रीप्रोसेसर को समस्याग्रस्त src फ़ाइल है और कोड के बड़े स्वार्थ को तब तक शुरू करना शुरू कर देता है जब तक कि वह उस त्रुटि के बिना संकलित न हो जाए। मुझे लगता है कि आप आसान रोलबैक के लिए किसी प्रकार का संस्करण नियंत्रण उपयोग कर रहे हैं। – greatwolf

उत्तर

1

क्योंकि टेम्पलेट्स संकलित नहीं किए जाते हैं जब तक कि आप ठोस तर्कों के साथ उन्हें कम नहीं करते।

संकलक लाइन की बात आती है:

myTree->addFirstToTree<ConcreteFirstA>(); 

यह तर्क ConcreteFirstA है, जो एक पूरी तरह से जाना जाता है प्रकार है के साथ पहली बार के लिए समारोह addFirstToTree संकलित करता है।

cplusplus.com - Templates

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

2

main.cpptree.h है, जो (परोक्ष रूप से) शामिल हैं समस्याग्रस्त addFirstToTree() टेम्पलेट, और concretefirsta.h, जो ConcreteFirstA की परिभाषा में शामिल भी शामिल है।

main.cpp में बाद में, addFirstToTree()ConcreteFirstA प्रकार के लिए instantiated है:

myTree->addFirstToTree<ConcreteFirstA>(); // <-- here! why is this working? 

इस बिंदु जहां संकलक पर्याप्त पर्याप्त टेम्प्लेट पैरामीटर के रूप में इस्तेमाल addFirstToTree() संकलक करने के लिए सक्षम होने के लिए प्रकार के बारे में पता करने के लिए की जरूरत है। और यह पर्याप्त जानता है। ConcreteFirstA यहां एक पूर्ण प्रकार है, क्योंकि concretefirsta.h शामिल हो गया है और इसमें क्लास परिभाषा शामिल है।


tree.tpp जहां addFirstToTree() परिभाषित हो जाता है में पर इससे पहले, ConcreteFirstA अभी तक परिभाषित नहीं है, लेकिन यह है कि कोई फर्क नहीं पड़ता। कंपाइलर एक टेम्पलेट देखता है और यह नहीं जानता कि टेम्पलेट पैरामीटर किस टेम्पलेट को बाद में चालू किया जाएगा। टेम्पलेट पैरामीटर ("आश्रित नाम") पर निर्भर किसी भी फ़ंक्शन/... को बिना किसी पैरामीटर के तत्काल पैरामीटर को जानने के लिए हल नहीं किया जा सकता है, ताकि नाम लुकअप/... बाद में बंद हो जाए।

एक बार टेम्पलेट तत्काल हो जाता है और संकलक सभी आश्रित नामों को हल करता है और विशिष्ट टेम्पलेट पैरामीटर के लिए टेम्पलेट संकलित करता है। चूंकि ConcreteFirstA उस बिंदु पर अधूरा प्रकार नहीं है, यह त्रुटियों के बिना काम करता है।

+0

हे! देर से उत्तर के लिए खेद है, मैं बीमार पड़ गया हूं और केवल जवाब देखने के लिए कुछ समय था। उत्तर के लिए टीवाई।तो मूल रूप से, केवल स्पष्टीकरण के लिए, मेरे कोड 'अन्य टीएफ (यह) '(' tree.tpp' में) के अन्य चिह्नित स्थान 'tree.tpp' _not_ के बावजूद काम कर रहे हैं' concretefirsta.h' सहित) क्योंकि केवल बाद में संकलित हो जाता है सब कुछ 'main.cpp' में शामिल हो जाता है? – penelope

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