简体   繁体   中英

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 ). Who is right, and where is the correct behavior specified in the C++ Standard?

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. [..]

and the only relevant part of auto 's semantics:

[C++11: 7.1.6.4/3]: Otherwise, the type of the variable is deduced from its initializer. [..]

(reminding us that the type of x is 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). 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; 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 . 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.

I believe GCC and Visual Studio are taking the following as inspiration:

[C++11: 7.1.6.4/5]: A program that uses auto in a context not explicitly allowed in this section is ill-formed.

…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 .

C++14 adds wording that relates to declarations of functions with deduced types:

[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. [..]

By symmetry one might suggest that, in your int case, it is intended that GCC and VS be correct in rejecting the program. 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. 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 :

A program that uses auto or decltype(auto) in a context not explicitly allowed in this subclause is ill-formed.

and we can see it makes a similar case for functions ill-formed in [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.

I'd imagine the restriction in [dcl.spec.auto]p11 exists because otherwise, that would allow:

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM