簡體   English   中英

使用“自動”的聲明是否與使用具體類型說明符的外部聲明匹配?

[英]Does a declaration using “auto” match an extern declaration that uses a concrete type specifier?

考慮以下程序:

extern int x;
auto x = 42;
int main() { }

Clang 3.5接受它( 實時演示 ),GCC 4.9和VS2013不接受( 前者的實時演示 )。 誰是正確的,在C ++標准中指定了正確的行為?

標准中對此幾乎沒有什么令人驚訝的。 關於重聲明,我們聽到的所有信息是:

[C++11: 3.1/1]:聲明(第7條)可以在翻譯單元中引入一個或多個名稱,也可以重新聲明由先前聲明引入的名稱。 [..]

以及auto語義的唯一相關部分:

[C++11: 7.1.6.4/3]:否則,將從變量的初始化程序中推斷出變量的類型。 [..]

(提醒我們x的類型為int )。

我們知道,所有聲明都必須為變量賦予相同的類型:

[C++11: 3.5/10]:在對類型進行所有調整之后(在其typedef(7.1.3)被其定義替換之前), 所有引用給定變量或函數的聲明所指定的類型應相同 ,除了數組對象的聲明可以指定因主要數組綁定的存在與否而不同的數組類型(8.3.4)。 違反此類型身份規則的規則不需要診斷。

“所有類型的調整之后”應該解決有關auto參與所有這些的任何問題; 因此,我的解釋是, 這本質上是在類型為int全局范圍內對x的有效重新聲明(和定義),並且Clang是正確的 即使我們建議不將auto視為“類型調整”,因為不需要診斷,最糟糕的是, 所有列出的實現都以自己的方式兼容。

我相信GCC和Visual Studio將從以下方面得到啟發:

[C++11: 7.1.6.4/5]:在本節中未明確允許的上下文中使用auto的程序[C++11: 7.1.6.4/5]:

…但是我認為這是短視的。 標准語言似乎不可能禁止通常的重新聲明規則,只是因為它們沒有在7.1.6.4被重復或未明確引用。

C ++ 14增加了與推導類型的函數聲明有關的措辭:

[C++14: 7.1.6.4/13]:具有使用占位符類型的已聲明返回類型的函數或函數模板的重新聲明或特化也應使用該占位符,而不是推導類型。 [..]

通過對稱有人可能會認為,在你的int的情況下,其意圖是GCC和VS是拒絕的程序是正確的。 但是,這是一個不同的功能(因為不能將推論僅用於聲明),因此是一個不同的方案。

無論哪種方式,改進的標准措辭都會在這里有所幫助。 我認為這是[合理的次要]編輯缺陷。

注意

回答了一個與該問題重復的問題。 我要求合並,卻被告知在此處提供答案 請參閱下面的原始答案。

更新叮當聲是正確的

我在推特上問了這個問題, 我從理查德·史密斯收到回復如下:

這不是缺陷,有意使此限制僅適用於推導的返回類型,而不適用於變量類型 對於變量,這只是方便的簡寫,但是返回類型推導會影響有關函數(尤其是函數模板)的更基本的內容。

因此,邏輯是[dcl.spec.auto]允許這樣做,並為推導返回類型限制了這一點,在此部分添加了[dcl.spec.auto]p11段落。 否則就沒有限制,因此對於變量情況沒有限制。

原版的

目前, [dcl.spec.auto]似乎並未[dcl.spec.auto]涵蓋這種情況,但它確實在[dcl.spec.auto] p5中指出:

在本款未明確允許的上下文中使用auto或decltype(auto)的程序格式錯誤。

我們可以看到,對於[dcl.spec.auto] p11格式不正確的函數,情況也是如此

具有使用占位符類型的已聲明返回類型的函數或函數模板的重新聲明或特化也應使用該占位符,而不是推導類型 同樣,具有聲明的返回類型且不使用占位符類型的函數或函數模板的重新聲明或特殊化也不應使用占位符 [示例:

 auto f(); auto f() { return 42; } // return type is int auto f(); // OK int f(); // error, cannot be overloaded with auto f() 

....

因此,盡管這可以按照當前的措詞進行澄清,但感覺gcc是正確的,而且格式不正確。

我以為[dcl.spec.auto] p11中存在限制,因為否則,這將允許:

int f();
auto f(); // What's the return type here?

事實是,您可以擁有一個具有函數返回類型的未推斷類型。 沒有基於先前聲明的推導規則,這就是為什么函數不允許這種混合的原因,即使以下情況完全可以:

int f();
auto f() { return 1; }

變量不存在此問題:

extern int v;
extern auto v; // ill-formed

任何僅用於聲明的變量都必須使用非占位符類型。 這意味着,如果將占位符類型用於v的定義,則可以毫無疑問地推導出它,然后當然必須匹配第一個聲明中使用的非占位符類型。

extern int v;
auto v = 1; // ok, type deduced as 'int', matches first declaration.

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM