2011-12-07 64 views
1

VS2010部分支持C++ 11。我在VS2010 RTM中編譯下面的代碼。我很困惑爲什麼代碼CLS()被分析到不同的含義。在「decltype(CLS())obj1;」行中,CLS()表示一個類對象實體。但是在「CLS obj2(CLS());」一行中,CLS()表示一個函數指針,該函數指針不帶參數地回退CLS對象。行爲是否預期?它在標準中有描述嗎?爲什麼CLS()在C++中有不同的含義11

struct CLS 
{ 
    int mi; 
}; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    decltype(CLS()) obj1; 
    obj1.mi = 10; 

    CLS obj2(CLS()); 
    obj2.mi = 10; // error C2228: left of '.mi' must have class/struct/union 

    return 0; 
} 

UPDATE 2011/12/8

每C++ 11 7.1.6.2/1,在括號中的期望的字符串是一個表達式。編譯器只需要檢查該字符串是否可以被解析爲有效的表達式。如果是,則代碼格式良好。因此,對於代碼「decltype(CLS())obj1;」,「CLS()」被視爲表示對象定義的有效表達式。

decltype-specifier: 
    decltype (expression) 

更新2012/1/3

Potatoswatter給出的解釋爲什麼 「CLS OBJ 2(CLS());」是除對象定義之外的聲明。

任何可以被解釋爲表達式或聲明的東西都是一個聲明,但它可能是不尋常的。 CLS obj2(CLS());聲明一個函數,其參數類型CLS()是一個沒有返回CLS參數的函數,其返回類型是CLS。

回答

1

正如其他人所說,這是最幸福的解析。任何可能被解釋爲表達式或聲明的東西都是一種聲明,但它可能是不尋常的。 CLS obj2(CLS());聲明瞭一個函數,其參數類型爲CLS()是一個沒有返回CLS參數的函數,其返回類型是CLS。

例如,

CLS obj2(CLS()); // forward declaration 

CLS obj2(CLS fun()) { // definition 
    return fun(); // use unusual functional argument 
} 

CLS foo() { // define a function to use as unusual argument 
    return CLS(); 
} 

int main() { 
    CLS obj2(CLS()); // still a forward declaration, even in this context! 

    CLS x = obj2(foo); 
} 

的解決方案是使用C++ 11的均勻初始化

CLS obj2{ CLS() }; 

或簡單地

CLS obj2{}; 
+0

「任何可能被解釋爲表達式或聲明的東西都是聲明」。在約翰內斯的評論中,他說錯了。我想再次與你確認,這是否正確?如果是的話,你能指出這個規則在C++標準中的定義嗎?我同意。 C++ 11語法避免了這種混淆。 – Jeffrey

+0

@Jeffrey:不,celtschk的錯誤陳述是關於聲明和*定義*之間的歧義。改變定義爲表達將是約翰內斯正在尋找的改正。 – Potatoswatter

+0

我很清楚。謝謝,Potatoswatter。 – Jeffrey

2

是,它預計:是

它被稱爲 「most vexing parse」。

CLS obj2(CLS()); // function forward declaration. 

CLS obj2 = CLS(); // Creates object zero initialized. 
CLS obj2;   // Creates object default initialized. 
+0

代碼「CLS OBJ3(OBJ1 ); \t obj3.mi = 10;「可以編譯成功。爲什麼「CLS obj2(CLS());」被視爲函數聲明,但「CLS obj3(obj1);」被視爲一個對象定義?他們有相似的形式。爲什麼不在「CLS obj2(CLS());」中的CLS()被視爲臨時對象定義? – Jeffrey

+0

因爲C++的語法很複雜:請看這裏:http://www.nongnu.org/hcb/#block-declaration –

+0

@Jeffrey:因爲'obj1'是一個變量,'CLS'是一個類型。 – ildjarn

1

在參數decltype中,預計有一個表達式。將CLS()解釋爲表達式的唯一方法是將其解析爲CLS類型的默認構造對象。

然而,在CLS obj2(CLS())(其BTW工作在相同的方式C++ 03)有可能解析:一個作爲函數聲明和一個作爲對象定義。作爲函數聲明,外部圓括號形成參數列表,並且內容需要通過給定類型和可選名稱來指定參數(或其列表)。在該解析中,CLS()被解釋爲函數類型。

其他有效的解析是作爲對象的定義。對於這種解析,當然在括號中必須有一個表達式(或它們的列表),將CLS()的解釋作爲CLS類型的默認構造對象。

現在在C++中有一條規則,如果某些東西既可以作爲聲明也可以作爲定義被解析,則它將被解析爲聲明。也就是說,在這種情況下,將使用第一種解釋。

這當然會引起的問題爲什麼第一種解釋是在我們明確期待第二種解釋時選擇的。答案是,否則它會破壞C兼容性(甚至在某些情況下甚至是我們的期望)。例如,看一下下面一行:

int f(); 

現在你會同意這個聲明的函數沒有參數和返回int,對不對?但它也可以被解析爲類型爲int的默認初始化變量的定義。由於上述規則,它確實聲明瞭返回int的函數。

總是給人一種期望的結果的規則在最好的情況下將是複雜的,但很可能是不可能的。

請注意,在C++ 03中,避免使用自動變量的簡單方法是用auto來定義前綴:由於函數聲明永遠不會以auto開頭,這會迫使編譯器將其解釋爲變量定義。由於在C++ 11中刪除了auto的舊含義,因此它不再有效(對於非自動變量,它永遠不會起作用)。

+2

「現在在C++中有一條規則,即如果某些東西既可以作爲聲明也可以作爲定義來解析,則它將被解析爲聲明,即在這種情況下,將使用第一種解釋。」 - >錯誤。 「由於函數聲明從不以auto開頭,所以這會迫使編譯器將其解釋爲變量定義。」 - >錯誤。 「但它也可以被解析爲int類型的默認初始化變量的定義。」 - >錯誤。請改正。 –

相關問題