繁体   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