2016-10-03 35 views
6

我很困惑如何編譯CRTP。如果我們有這樣的事情:爲什麼CRTP不會造成無限嵌套?

template<class T> 
class Base 
{ 

}; 
class Derived : public Base<Derived> 
{ 

}; 

爲什麼在編譯過程中不會出現類似這種情況?

X[Y]表示X與Y繼承)

在一個Derived實例 Derived d;

d被擴展成的模板和繼承

d[Base<Derived[Base<Derived[Base<Derived[Base<Derived[...]>]>]>]>]

爲什麼無限復發的聲明這是不是發生?關於CRTP的所有教程只解釋你可以用它做什麼,而不是發生在引擎蓋下(至少隱約)。

+0

在'Base'的背景下,'T'不是一個完整的類型。正因爲如此,你不能像'Base'那樣訪問'T'中定義的'typedef'(參見[1](http://stackoverflow.com/questions/6006614/c-static-polymorphism-crtp- and-using-typedefs-from-derived-classes)和[2](http://stackoverflow.com/questions/652155/invalid-use-of-incomplete-type))。由於'T'不是一個完整的類型,因此編譯器在這種情況下不需要無限遞歸。至少這是我的理解。 – Cornstalks

+0

@Eichhörnchen因爲我從Base派生,它由Derived模板化,它繼承自Base,由Derived模板化,它繼承自Base ... –

+0

@Cornstalks yea聽起來正確 –

回答

7

的基本概念理解的是,一個模板的實例就是一個類。它從根本上與其他任何課程沒有什麼不同。

當你有一個典型的模板定義:

template<typename T> class Base; 

然後模板實例:

Base<int> 

僅僅是一個類名。它與int無關,並且與int完全沒有任何關係。它不以某種方式或以任何方式繼承它。

下一步:

class Derived; 

template<typename T> class Base {}; 

Base<Derived> foo; 

再次,Base<Derived>僅僅是一個類。它與Derived沒有內在關係。它不是從它派生出來的,也不是從它繼承而來,沒有任何東西。

所以,現在我們採取的最後一步:

template<class T> 
class Base 
{ 

}; 

class Derived : public Base<Derived> 
{ 

}; 

聲明一個叫做Derived類,它從一個名爲Base<Derived>類繼承。而Base<Derived>只是一個類。這是一個非常簡單的課程。沒有比這更簡單的了。它沒有任何方法。它沒有任何成員。也不是私人的,受保護的或公共的。這是一個小課堂,但它擁有與任何其他課程相同的權利和特權。你可以聲明一個指針。或者是對它的引用。這只是一堂課。

此外,關鍵概念是模板的實例只是一個類。它不以任何方式從作爲參數的類繼承到模板。在這種情況下,模板實例是完全空的,但它可以做任何其他類可以做的事情。它可以有公共,私人和受保護的成員。它可以派生自其他一些類,這可能是另一個模板實例(因爲模板實例只是一個類)。或者,其他類可以從模板實例派生,因爲模板實例只是一個類。

這裏沒有無限的嵌套。你只有一個類從另一個類繼承。第二類碰巧是一個模板實例,但是我碰巧提到模板實例只是一個類?

3

簡單的解釋:因爲以下是完全有效的:

template<class T> 
class Base 
{ 
}; 

class Derived /* at this point, Derived is declared (not defined) */; 

int main() 
{ 
    Base<Derived> base; // the definition of Derived (or lack thereof) is irrelevant. 
}