The snippet below compiles (demo):
struct A{ int i = 10; };
int main() {
struct A{ int i = 20; };
struct A;
struct A a;
}
But this doesn't:
struct A{ int i = 10; };
int main() {
// struct A{ int i = 20; };
struct A;
struct A a;
}
I can see that the answer is probably given by these paragraphs in the Standard:
[basic.lookup.elab]/2 and [basic.scope.pdecl]/7.
But I really don't know how to deduce the different behaviors shown above from these two paragraphs.
Note that in the first example the struct A
is not first declared in the elaborated-type-specifier struct A;
, but in the definition of struct A
in main()
.
In the second example, the struct A
is also not first declared in the elaborated-type-specifier struct A;
, but in the definition of struct A
in global scope.
Each of the examples contains declarations of two different classes, both with the name A
.
Let's distinguish between the classes by renaming one of them to B
:
struct A{ int i = 10; };
int main() {
struct B{ int i = 20; };
struct B;
struct B b;
}
The above is semantically identical to your first example. The class A
is never used.
struct A{ int i = 10; };
int main() {
struct B;
struct B b;
}
This is semantically identical to your second example. You are trying to create an object of an incomplete type, the forward-declared class B
.
Renaming B
back to A
doesn't change anything because then the declaration of A
in main
shadows the declaration of the other A
at global scope.
[basic.lookup.elab]/2
If the elaborated-type-specifier has no nested-name-specifier, and [...] if the elaborated-type-specifier appears in a declaration with the form:
class-key
attribute-specifier-seq
optidentifier
;
the elaborated-type-specifier is a declaration that introduces the class-name as described in [basic.scope.pdecl].
So struct A;
is a declaration that introduces the class name in the scope of the declaration. Under no circumstances can it refer to a class declared in an outer scope.
[basic.scope.pdecl]/7
[ Note: Other forms of elaborated-type-specifier do not declare a new name [...] — end note ]
By implication, this form of elaborated-type-specifier declares a new name.