2015-10-15 70 views
1

我的問題是,爲什麼下面的代碼無法編譯:爲什麼類級別的typedef不是從tempates繼承的?

template<typename t> class c1 
{ 
public: 
    typedef int type_name; 
    void fn1(type_name x) {} 
}; 

template<typename t> class c2 : public c1<t> 
{ 
public: 
    void fn2(type_name x) {} 
}; 

雖然以下作用:

class c1 
{ 
public: 
    typedef int type_name; 
    void fn1(type_name x) {} 
}; 

class c2 : public c1 
{ 
public: 
    void fn2(type_name x) {} 
}; 

正如你看到的,唯一的區別是,在第一種情況中的類模板。 Gcc和Clang抱怨type_name沒有在第二個類中定義(僅在模板版本中)。 typedef是不是從父類繼承的?如果是這樣,爲什麼它在非模板版本上工作?從模板使用typedefs時是否有一些例外情況?

此外,我知道我可以使用完全限定類型名稱來工作,即'typename c1 :: type_name'。我只想知道這是否是一些C++限制或編譯器錯誤。

+0

那麼,模板類取決於模板參數,它們不會自動轉發。 –

回答

2

他們實際上是「繼承」(我的意思是他們可以作爲c2<t>的成員訪問)。但是,當編譯器有理由相信它們是從屬的時,只能在類模板內查找從依賴基類(依賴於模板參數的基類)繼承的所有成員(不僅僅是類型)。

換句話說,解析模板c2的定義時,編譯器不知道實例時t將是什麼,所以它有猜測c1<t>的定義是什麼沒有辦法(請記住,這可能以後專業化)。因此,在查找c2中的名稱時,根本不會查看c1。因此找不到type_name。但是,如果你使名稱查找以某種方式顯式依賴於模板參數,編譯器將意識到它必須推遲查找直到實例化。這會發生在這些情況下:

// Case 1 
template<typename t> class c2 : public c1<t> 
{ 
public: 
    void fn2(typename c1<t>::type_name x) {} 
}; 

// Case 2 
template<typename t> class c2 : public c1<t> 
{ 
public: 
    void fn2(typename c2::type_name x) {} 
}; 

在這兩種情況下,事情的::左側取決於模板參數,所以編譯器會知道推遲查找,直到實例化。

另請注意,您需要添加typename關鍵字;如果沒有它,編譯器將不知道::的權利是一種類型還是一種非類型成員。語言標準規定在這種情況下將其視爲非類型成員,這會導致語法錯誤。

但是,當c2不是模板時,它的所有基類的定義在解析時是完全已知的,所以在查找名稱時沒有問題。

您可以在此somewhat related SO question中瞭解有關此兩階段查找的更多詳細信息。

相關問題