The first snippet below compiles, but the second doesn’t. Why?

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-seqopt identifier ;

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.

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)