2012-08-11 96 views
5

考慮下面的代碼:當未返回未定義對象類型的引用的C++函數的返回值時,會發生什麼?

class Foo; 

Foo& CreateFoo(); 


void Bar() 
{ 
    CreateFoo(); 
} 

在Visual Studio中,這將導致錯誤C2027 foo是一個未定義的類型。在大多數其他編譯器中,它編譯得很好。如果沒有分配CreateFoo的返回值,這只是一個問題。如果我將該行更改爲:

Foo& foo = CreateFoo(); 

它在Visual Studio中編譯得很好。此外,如果Foo被定義而不是隻是前向聲明,那麼它將在沒有賦值的情況下編譯好。

哪個應該是正確的行爲?在C++標準中有沒有解決這個問題的東西,還是這是留給實施的東西?我看了看,沒有看到有關這件事的任何內容。

更新: A bug report has been filed.

+0

哪個版本的Visual C++編譯器?版本之間的法規遵從性變化很大 – 2012-08-11 01:28:06

+0

這看起來像一個Visual C++編譯器錯誤(我同意Ben Voigt對規範的分析,並且'CreateFoo();'和'Foo&foo = CreateFoo();'之間的行爲差​​異很奇怪)。我沒有看到這個問題存在一個缺陷,並且它使用Visual C++ 2012重新生成。如果這個問題對您很重要,請考慮在[Microsoft Connect]上打開一個錯誤(http://connect.microsoft.com/ VisualStudio /)並在此發佈鏈接以供將來參考。謝謝! – 2012-08-11 01:28:24

+0

VS2010提交了一個錯誤報告,但它被標記爲nofix,因爲它是一個記錄的限制。他們沒有提供關於它是否合規的意見。 VS2010中C2027的MSDN頁面顯示相同類型的問題。 http://msdn.microsoft.com/en-us/library/6c2dk0ah.aspx請參見上一節。它實際上表示不允許對未定義類型的引用,但事實並非如此,它只是在它未被分配返回值時纔出現,這在他們的示例代碼中就是這種情況。 – Gerald 2012-08-11 01:34:51

回答

6

這看起來像標準的相關部分(第5.2.2節):

函數調用是一個左值如果結果類型是左值引用類型或對函數 類型的右值引用,如果結果類型是對對象類型的右值引用,則爲xvalue,否則爲prvalue。

如果函數調用是對象類型的prvalue:

  • 如果函數調用或者是

    • 一個decltype說明符的操作數

    • 逗號運算符的右操作數,它是decltype-specifier的操作數

    沒有爲prvalue引入臨時對象。價值的類型可能不完整。 [注意:因此,存儲沒有分配給prvalue,它不會被破壞;因此,一個類的類型是 沒有實例化,作爲在這種情況下函數調用的類型的結果。無論 是否表達式使用函數調用符號或運算符表示法(13.3.1.2),情況都是如此。 - 注意:[注意: 不同於decltype說明符的規則,它考慮id表達式是否用括號括起來(7.1.6.2), 括號在此上下文中沒有特殊含義。 - 結束註釋]

  • 否則,應該完成預估的類型。

由於此函數結果類型爲左值引用類型,函數調用的計算結果爲一個左值,和完整性的要求並不適用。

該代碼是合法的,至少在C++ 11中,沒有發佈版本的Visual C++完全實現。

+0

謝謝,這是關於我的想法,但不能把它壓下。 – Gerald 2012-08-11 01:37:44

1

您可以在函數聲明中始終使用不完整的類型(因爲它只聲明函數的簽名,而不是任何實際的代碼),但在您使用它時不會使用它。

調用CreateFoo();等於(void) CreateFoo();,我的猜測是Visual Studio需要檢查Foo的代碼以進行任何轉換(我不確定是否可以實際編寫無效轉換),因爲對於轉換需要一個完整的類型。

至於Foo & foo = CreateFoo();,這不會做任何轉換,所以你可以逃避一個不完整的類型。

+0

謝謝,這對VS爲什麼不處理它會發光一點。做Foo&foo = CreateFoo(); (空隙)FOO;導致相同的錯誤。這似乎表明它確實是一個違規問題,因爲標準規定:「任何表達式都可以顯式轉換爲cv void類型,在這種情況下,它將成爲一個丟棄值表達式」。 – Gerald 2012-08-11 02:14:19

相關問題