2014-09-25 46 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 2014-12-24 07:56:32

回答

1

因爲在使用具體參數對模板進行實例化之前不會編譯模板。

當編譯器涉及到行:

myTree->addFirstToTree<ConcreteFirstA>(); 

它編譯函數addFirstToTree首次用參數ConcreteFirstA,這是一個完全已知類型那裏。

cplusplus.com - Templates

他們都編上的需求,這意味着直到需要與特定的模板參數實例化一個模板函數的代碼不編譯。此時,當需要實例化時,編譯器將專門爲模板中的參數生成一個函數。

2

main.cpp包括tree.h,其中包含(間接地)有問題的addFirstToTree()模板,concretefirsta.h,其中包含的ConcreteFirstA定義。

main.cpp後來,addFirstToTree()被實例化的ConcreteFirstA類型:

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

這是編譯器需要有足夠的瞭解作爲模板參數,以便能夠編譯addFirstToTree()類型足夠的點。它確實知道得夠多。 ConcreteFirstA在這裏是一個完整的類型,因爲concretefirsta.h被包含幷包含類定義。


tree.tpp其中addFirstToTree()被定義早前,ConcreteFirstA還沒有定義,但是,這並不重要。編譯器看到一個模板,並不知道該模板稍後將被實例化的模板參數。任何取決於模板參數(「依賴名稱」)的函數/ ...都不能在不知道模板將被實例化的參數的情況下被解析,以便名稱查找/ ...被放棄,直到稍後。

模板實例化後,編譯器解析所有相關名稱並編譯特定模板參數的模板。由於ConcreteFirstA在這一點上不是不完整的類型,所以這個工作沒有錯誤。

+0

嘿!對不起,遲到的回覆,我已經生病了,只有現在有一段時間來查看答案。 TY爲答案。所以基本上,只是爲了澄清,我的代碼'新TF(this)'(在'tree.tpp')中的另一個標記點​​正在工作,儘管'tree.tpp'_not_不包括'concretefirsta.h',因爲只有在得到一切都包含在'main.cpp'中? – penelope 2014-10-02 09:08:34

相關問題