2011-08-26 131 views
14

我非常驚訝的是,在克各種採樣版本++,下面編譯沒有錯誤或警告:不完整的類使用模板

// Adapted from boost::checked_delete() 
template <class T> inline void assert_complete() 
{ 
    typedef char type_must_be_complete[ sizeof(T) ? 1 : -1 ]; 
    (void) sizeof(type_must_be_complete); 
} 

class X; 

void f() 
{ 
    assert_complete<X>(); 
} 

class X {}; 

int main() {} 

如果X定義丟失或在不同的翻譯單元,我確實會得到錯誤。

但是在上面的程序中,是不是我的模板的單個實例化點的定義是f?那個實例化的X不是不完整的語義錯誤?

(C++ 03和/或C++ 11 Draft)標準調用這個程序是否格式良好,格式不正確,格式不正確,診斷不需要,或者是未定義的行爲?

編輯:@David Rodriguez - dribeas報告稱,clang ++,comeau和Visual Studio 2010也接受類似的代碼。只要該類型是在翻譯單元則任何早期完整實例將完成地方完成

class X {}; 

+0

有趣的是,當我爲'X'的定義添加一個'int'時,'sizeof(T)'爲4。過去已知模板具有預知能力。 –

回答

12

(我等着阿爾夫施泰因巴赫發佈一個答案,但因爲他沒有這樣做,我會後,他在休息室C++聊天中提到的參考):

標準表明,模板在之後執行實例化,翻譯單元已經被翻譯,以便及時,在之後發生模板實例所有非模板元素已經被處理。這是第2.2階段翻譯描述:

第1-6段定義預處理工作和基本文本操作(字符集的轉換,文字的串聯......)

7 /分隔令牌的空白字符不再重要。每個預處理令牌都被轉換爲令牌。 (2.7)。所產生的令牌在語法和語義上被分析並翻譯爲翻譯單元。

8翻譯單元和實例化單元如下組合:檢查每個翻譯的翻譯單元以產生所需實例的列表。所需模板的定義已定位。它是實現定義的,包含這些定義的翻譯單元的來源是否需要可用。所有必需的實例化都被執行以產生實例化單元。 [注意:這些翻譯單位與翻譯單位類似,但不包含對未經實例化的模板的引用,也不包含模板定義。 - 結束註釋]如果任何實例化失敗,則該程序不合格。

爲了簡潔,我已經刪除了一些註釋。現在重要的一點似乎是代碼翻譯時不會一步觸發模板實例化,然後在稍後的步驟中實例化模板。這又意味着如果翻譯單元中的任何地方的類型是完成,則在編譯器進入實例化時它將被處理。

免責聲明:這似乎是一個很好的理由,所有我曾嘗試顯示完全相同的行爲(GCC,鐺,科莫,VS 2010)的編譯器,但這只是國家在時間上的實例被執行時,它沒有明確說明該類型在模板實例化時可能是不完整的。

+0

spencercw的回答和評論似乎表明它在標準的其他地方明確允許。 –

+0

@MatthewWalton:spencercw的答案與此問題無關。如果不是函數模板而是一個非模板,那麼代碼將無法編譯,因爲ashepler在他的評論中指向spencercw的答案,標識符在所有TU中指向相同類型的事實並不意味着在那裏在遇到類型定義之前(即仍然不完整),對你可以做什麼或不做什麼*沒有限制。 –

+0

具體問題是關於爲什麼'int size1(){return sizeof(X); }'如果'X'不是不完整,*在這個點*不會被編譯,而'template size 012(){return sizeof(T)}'將被編譯,即使類型在*實例化點不完整, spencercw的答案不處理這種差異。 –

6

該行完成的類型。

下面是來自標準的相關部分[basic.types](3.9第7段):

的類型(例如,「類X」)可能是在一個點上不完全在一個翻譯單元和稍後完成;兩個點的類型「class X」是相同的類型。數組對象的聲明類型可能是不完整類類型的數組,因此不完整;如果稍後在翻譯單元中完成類類型,則數組類型變爲完整;這兩點的數組類型是相同的類型。數組對象的聲明類型可能是未知大小的數組,因此在翻譯單元中的某一點不完整,稍後完成;這兩個點的數組類型(「T的未知邊界數組」和「N T數組」)是不同的類型。無法完成指向未知大小數組的指針的類型,或由typedef聲明定義爲未知大小數組的類型的指針的類型。

+1

但是,即使稍後在TU中完成,也有很多事情你不能完成的類型,即使它尚未完成。嘗試從模板中取出模板:'class X; void f(){(void)sizeof(X); } class X {};'肯定會導致錯誤。 – aschepler

+0

啊,是的,我明白你的觀點;看起來我可能誤解了規範。但是,[temp.arg.type]聲明「模板類型參數可能是不完整的類型」,我想它允許它使用稍後在翻譯單元中定義的完整類型。 – spencercw

相關問題