2016-08-15 71 views
3

我看到了一個代碼在這裏Cpp Quiz [問題#38]最讓人頭疼的解析

#include <iostream> 

struct Foo 
{ 
    Foo(int d) : x(d) {} 
    int x; 
}; 

int main() 
{ 
    double x = 3.14; 

    Foo f(int(x)); 

    std::cout << f.x << std::endl; 

    return 0; 
} 

據說那裏,這個代碼是非法的形成,因爲Foo f(int(x));將作爲函數聲明,而不是一個對象聲明來處理請輸入Foo。據我所知,這是最令人頭疼的解析實例。我的問題是這是什麼語法int(x)在聲明Foo f(int(x));意味着什麼?到目前爲止,我只看到了函數聲明,如:

  1. Foo f(int);

  2. Foo f(int x);

同樣是它作爲Foo f(int x);

回答

2

這是什麼語法int(x)在語句Foo f(int(x));的意思?

圍繞x的括號是多餘的,將被忽略。所以int(x)int x相同,表示x的參數,其類型爲int

是否與Foo f(int x);相同?

是的。 Foo f(int(x));是函數聲明,其名稱爲f,返回Foo,取一個名爲x的參數,其類型爲int

下面是標準的解釋。 $8.2/1 Ambiguity resolution [dcl.ambig.res]

(重點煤礦)

從函數式 澆鑄和在[stmt.ambig]提及,也可能發生在一個聲明的 上下文中聲明之間的相似性所引起的二義性。在這種情況下,選擇範圍在 函數聲明與一個圍繞着 參數名稱的冗餘括號的函數聲明和函數樣式類型爲 的初始值設定項的對象聲明之間。正如 [stmt.ambig],中提到的含糊之處,決議是考慮任何構造,其可能是 可能是聲明。 [注意:一個聲明可以是 通過在參數周圍添加括號來明確地消除歧義。 可通過使用複製初始化或列表初始化語法或使用非函數樣式轉換來避免歧義。 - 注完] [實施例:

struct S { 
    S(int); 
}; 

void foo(double a) { 
    S w(int(a));  // function declaration 
    S x(int());  // function declaration 
    S y((int(a))); // object declaration 
    S y((int)a);  // object declaration 
    S z = int(a);  // object declaration 
} 

- 端示例]

所以,int(x)將被視爲(參數)的聲明,而不是函數樣式轉換。

4

問題是,出於我未知的原因,將參數名稱包裝到原型中的括號是有效的。所以

Foo f(int(x)); 

可以解釋爲

Foo f(int x); 

被認爲不過是

Foo f(int); 

真正的問題是,C++的作者,也不知爲什麼對我來說,決定是對於幾乎完全相同的語義(實例初始化),酷派有兩種不同的語法形式。

這引入了一種語法歧義,通過說「如果某件事既可以是聲明又可以是定義,那麼它就是聲明」來觸發陷阱,從而「解決」語法歧義。

因此,C++解析器因此必須能夠解析任意數量的標記,然後才能決定第一個標記的語義。

除了編譯器編寫器,這顯然不會有太多的問題,但是它意味着讀取C++代碼來理解它的人也必須能夠做同樣的事情,而且對於我們人類來說這很難。從那個「最煩人的」。

+1

這是允許的,因爲有時需要它 - 例如使'int * a [10]'與'int(* a)[10]'不同。沒有人會花時間在必要時將語法限制爲* only *。 –

+0

@BoPersson:我在[關於最煩人的分析](http://stackoverflow.com/questions/7007817/a-confusing-detail-about-the-most-vexing-parse)的混淆細節中看到了代碼,以及老實說,我不明白它:(。 – NeonGlow

+0

@NeonGlow ruls是一樣的,期望該函數有兩個參數,第二個是函數指針。 – songyuanyao