简体   繁体   English

使用“自动”的声明是否与使用具体类型说明符的外部声明匹配?

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

Consider the following program: 考虑以下程序:

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

Clang 3.5 accepts it ( live demo ), GCC 4.9 and VS2013 do not ( live demo for the former ). Clang 3.5接受它( 实时演示 ),GCC 4.9和VS2013不接受( 前者的实时演示 )。 Who is right, and where is the correct behavior specified in the C++ Standard? 谁是正确的,在C ++标准中指定了正确的行为?

There's surprisingly little in the standard about this. 标准中对此几乎没有什么令人惊讶的。 About all we hear about redeclaration is: 关于重声明,我们听到的所有信息是:

[C++11: 3.1/1]: A declaration (Clause 7) may introduce one or more names into a translation unit or redeclare names introduced by previous declarations. [C++11: 3.1/1]:声明(第7条)可以在翻译单元中引入一个或多个名称,也可以重新声明由先前声明引入的名称。 [..] [..]

and the only relevant part of auto 's semantics: 以及auto语义的唯一相关部分:

[C++11: 7.1.6.4/3]: Otherwise, the type of the variable is deduced from its initializer. [C++11: 7.1.6.4/3]:否则,将从变量的初始化程序中推断出变量的类型。 [..] [..]

(reminding us that the type of x is int ). (提醒我们x的类型为int )。

We know that a variable must be given the same type by all declarations: 我们知道,所有声明都必须为变量赋予相同的类型:

[C++11: 3.5/10]: After all adjustments of types (during which typedefs (7.1.3) are replaced by their definitions), the types specified by all declarations referring to a given variable or function shall be identical , except that declarations for an array object can specify array types that differ by the presence or absence of a major array bound (8.3.4). [C++11: 3.5/10]:在对类型进行所有调整之后(在其typedef(7.1.3)被其定义替换之前), 所有引用给定变量或函数的声明所指定的类型应相同 ,除了数组对象的声明可以指定因主要数组绑定的存在与否而不同的数组类型(8.3.4)。 A violation of this rule on type identity does not require a diagnostic. 违反此类型身份规则的规则不需要诊断。

and the "after all adjustments of types" ought to take care of any questions regarding auto 's participation in all of this; “所有类型的调整之后”应该解决有关auto参与所有这些的任何问题; my interpretation, then, is that this is inherently a valid redeclaration (and definition) of the x at global scope with type int , and that Clang is correct . 因此,我的解释是, 这本质上是在类型为int全局范围内对x的有效重新声明(和定义),并且Clang是正确的 Even if we propose that auto does not count as "adjustment of type", since no diagnostic is required, at worst all listed implementations are compliant in their own way. 即使我们建议不将auto视为“类型调整”,因为不需要诊断,最糟糕的是, 所有列出的实现都以自己的方式兼容。

I believe GCC and Visual Studio are taking the following as inspiration: 我相信GCC和Visual Studio将从以下方面得到启发:

[C++11: 7.1.6.4/5]: A program that uses auto in a context not explicitly allowed in this section is ill-formed. [C++11: 7.1.6.4/5]:在本节中未明确允许的上下文中使用auto的程序[C++11: 7.1.6.4/5]:

…but I think that this is short-sighted. …但是我认为这是短视的。 It seems unlikely that the standard language is intended to prohibit the usual redeclaration rules, just because they are not repeated or explicitly referenced from within 7.1.6.4 . 标准语言似乎不可能禁止通常的重新声明规则,只是因为它们没有在7.1.6.4被重复或未明确引用。

C++14 adds wording that relates to declarations of functions with deduced types: C ++ 14增加了与推导类型的函数声明有关的措辞:

[C++14: 7.1.6.4/13]: Redeclarations or specializations of a function or function template with a declared return type that uses a placeholder type shall also use that placeholder, not a deduced type. [C++14: 7.1.6.4/13]:具有使用占位符类型的已声明返回类型的函数或函数模板的重新声明或特化也应使用该占位符,而不是推导类型。 [..] [..]

By symmetry one might suggest that, in your int case, it is intended that GCC and VS be correct in rejecting the program. 通过对称有人可能会认为,在你的int的情况下,其意图是GCC和VS是拒绝的程序是正确的。 However, this is a different feature (since deduction cannot be applied to mere declarations) and thus a different scenario. 但是,这是一个不同的功能(因为不能将推论仅用于声明),因此是一个不同的方案。

Either way, improved standard wording would help here. 无论哪种方式,改进的标准措辞都会在这里有所帮助。 I consider it a [reasonably minor] editorial defect. 我认为这是[合理的次要]编辑缺陷。

Note 注意

I answered a question that was closed a duplicate of this one. 回答了一个与该问题重复的问题。 I asked for merge and was told instead to provide an answer here . 我要求合并,却被告知在此处提供答案 See below for my original answer. 请参阅下面的原始答案。

Update clang is correct 更新叮当声是正确的

I asked this question on twitter and the response I received from Richard Smith was as follows: 我在推特上问了这个问题, 我从理查德·史密斯收到回复如下:

Not a defect, it's intentional that this restriction applies only to deduced return types and not to variable types . 这不是缺陷,有意使此限制仅适用于推导的返回类型,而不适用于变量类型 For variables, it's just a convenience shorthand, but return type deduction affects something more fundamental about functions (and especially function templates). 对于变量,这只是方便的简写,但是返回类型推导会影响有关函数(尤其是函数模板)的更基本的内容。

So the logic is that this is allowed by [dcl.spec.auto] and to restrict this for deduced return types paragraph [dcl.spec.auto]p11 was added to the section. 因此,逻辑是[dcl.spec.auto]允许这样做,并为推导返回类型限制了这一点,在此部分添加了[dcl.spec.auto]p11段落。 Otherwise there is no restriction and therefore this is not restricted for the variables case. 否则就没有限制,因此对于变量情况没有限制。

Original 原版的

Currently [dcl.spec.auto] does not seem to cover this case explictly but it does say in [dcl.spec.auto]p5 : 目前, [dcl.spec.auto]似乎并未[dcl.spec.auto]涵盖这种情况,但它确实在[dcl.spec.auto] p5中指出:

A program that uses auto or decltype(auto) in a context not explicitly allowed in this subclause is ill-formed. 在本款未明确允许的上下文中使用auto或decltype(auto)的程序格式错误。

and we can see it makes a similar case for functions ill-formed in [dcl.spec.auto]p11 : 我们可以看到,对于[dcl.spec.auto] p11格式不正确的函数,情况也是如此

Redeclarations or specializations of a function or function template with a declared return type that uses a placeholder type shall also use that placeholder, not a deduced type . 具有使用占位符类型的已声明返回类型的函数或函数模板的重新声明或特化也应使用该占位符,而不是推导类型 Similarly, redeclarations or specializations of a function or function template with a declared return type that does not use a placeholder type shall not use a placeholder . 同样,具有声明的返回类型且不使用占位符类型的函数或函数模板的重新声明或特殊化也不应使用占位符 [ Example: [示例:

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

.... ....

So although this could use clarification as currently worded it feels like gcc is correct and this is ill-formed. 因此,尽管这可以按照当前的措词进行澄清,但感觉gcc是正确的,而且格式不正确。

I'd imagine the restriction in [dcl.spec.auto]p11 exists because otherwise, that would allow: 我以为[dcl.spec.auto] p11中存在限制,因为否则,这将允许:

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

The thing is, you can have an undeduced type type has the return type of a function. 事实是,您可以拥有一个具有函数返回类型的未推断类型。 There are no deduction rules based on previous declarations, which is why such mixing is disallowed for functions, even though the following would be perfectly fine: 没有基于先前声明的推导规则,这就是为什么函数不允许这种混合的原因,即使以下情况完全可以:

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

This problem does not exist for variables: 变量不存在此问题:

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

Any declaration-only variables has to use a non-placeholder type. 任何仅用于声明的变量都必须使用非占位符类型。 What this means is that if you use a placeholder type for the definition of v , it can get deduced without any problems and then of course has to match the non-placeholder type used in the first declaration. 这意味着,如果将占位符类型用于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