Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I just read this answer, and it completely puzzles me.

I was always thinking a class declaration can appear many times, and only the definition has to exist only once, like:

/*class Class {*/

    class A;         // (1) forward declaration

    class A {        // (2) definition, only once
       int m;
    };

    class A;         // (3) declaration again, legal?

    class A a;       // (4) declaration again, legal?

/*};*/

From the linked answer: (3) (and (4)?) is illegal if the code above is nested inside a class (definition and declarations of class A are nested inside class Class).

On cppreference, I found an example of the above, not nested:

struct s { int a; };
struct s; // does nothing (s already defined in this scope)
void g() {
    struct s; // forward declaration of a new, local struct "s"
              // this hides global struct s until the end of this block
    s* p;     // pointer to local struct s
    struct s { char* p; }; // definitions of the local struct s
}

See the second line.

Question: Given that it is illegal inside a class, is my example code, and the cppreference example above, legal when not nested inside a class? Or more generally: When can a class declaration follow a definition (how is it inside namespaces for example)? If it is legal, why is there a difference?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
456 views
Welcome To Ask or Share your Answers For Others

1 Answer

From [basic.def]:

A declaration (Clause 7) may introduce one or more names into a translation unit or redeclare names introduced by previous declarations.

From [class.name]:

A declaration consisting solely of class-key identifier; is either a redeclaration of the name in the current scope or a forward declaration of the identifier as a class name. It introduces the class name into the current scope.

So it's generally legal to do this. There's just the one exception in [class.mem]:

A member shall not be declared twice in the member-specification, except that a nested class or member class template can be declared and then later defined, and except that an enumeration can be introduced with an opaque-enum-declaration and later redeclared with an enum-specifier.

Perfectly OK in namespace scope, not allowed in class scope.


As to why? Well, this rule let's you "forward" declare all the classes you need everywhere you would typically be allowed to do so:

// a.h
struct C;

struct A {
    C* c;
};

// b.h
struct C;

struct B {
    C& c;
};

without having to worry about somebody actually including the full declaration and breaking everything for you:

// d.h
#include "c.h"
#include "a.h" // now C was already declared!
#include "b.h" // and here too!

struct D { ... };

This isn't so much of a concern within a class definition. It can't exactly span multiple files. So the inability to redeclare nested types doesn't actually achieve anything.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...