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