According to the C++ standard, declaring a variable with the same name as a type is correct code in general, but invalid code within a class definition. The class case is specific, because names declared in a class definition are visible within the whole class definition, before and after the point of declaration of that name. In other scopes (global, namespace, function, ...) declared names are visible only after the point of declaration.
For the example given in the question: If you have another reference to foo
before the member declaration foo foo;
,
struct S { foo another_member; foo foo; };
to which foo
should it refer? To the type or the member foo
? In this case it would be possible to deduce from the context that the type is meant, but the C++ standard probably avoided complexity for treating corner cases.
But foo foo;
is valid code outside of class definitions: Additionally to the excerpt from section [dcl.spec], which Serge Ballesta already citied in his answer, section [dcl.decl] is useful in this context. It gives a valid example for this case (in older versions of the C++ standard text in a note below the text, in later versions as part of the main text) - here from the N3242 draft (final draft for C++11):
A declaration with several declarators is usually equivalent to the corresponding sequence of declarations each with a single declarator. That is
T D1, D2, ... Dn;
is usually equvalent to
T D1; T D2; ... T Dn;
where T
is a decl-specifier-seq and each Di
is an init-declarator.
The exception occurs when a name introduced by one of the declarators
hides a type name used by the decl-specifiers, so that when the same
decl-specifiers are used in a subsequent declaration, they do not have
the same meaning, as in
struct S ... ;
S S, T; // declare two instances of struct S
which is not equivalent to
struct S ... ;
S S;
S T; // error
The excerpt from section [dcl.spec] is useful as well, as it describes, when a name in a declaration of a variable is interpreted as type name and when as the variable name (long quote is given in Serge Ballesta's answer):
... it is interpreted as part of the decl-specifier-seq if and only if
...
The relevant section for the class' case, which is given in the original question, was [basic.scope.class]/2 in C++17:
... A name N used in a class S shall refer to the same declaration in its context and when re-evaluated in
the completed scope of S. No diagnostic is required for a violation of this rule. ...
This means that the code of the original question is invalid, but the compiler does not need to give an error. So both clang and gcc behave correctly (according to the C++ standard).
-fpermissive
switch... but why would you do that rather then fix the code!? I'd rather get an error that have it quietly accepted, hiding future maintenance problems. – Exit-fpermissive
theerror
is converted towarning
. But the problem remains. Put this statement in any class method and it results in error:auto x = foo(5);
Moreover, I think the OP isn't introducing such naming deliberately in the code. Mostly it's a curiosity question, which even I had many years back regarding this exact topic. That's why reopened this question. – Tenotomy