Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't this C++ code give compilation error?

#include<iostream>
using namespace std;

struct a{
    int e;
    struct abc *d;
};

struct abc{
    int c;
};

int main()
{
 return 0;  
}

I have defined the struct abc after definition of struct a in which i have declared a structure pointer for abc. This is supposed to throw compilation error because abc is used before its declaration. But, it doesn't, why? Whereas when i replace it with just struct abc d instead of struct abc *d, it is giving compilation error as expected.

like image 499
Nikita Neema Avatar asked Dec 19 '22 01:12

Nikita Neema


2 Answers

This declaration

struct abc *d;

on the one hand declares struct abc and on the other hand declares pointer d of type struct abc *.

In this declaration there is no need to have the exact definition of struct abc because no data member of the structure is used.

This specifier struct abc is called elaborated type specifier.

It introduces a new type in the given scope or refers to an already declared type.

like image 75
Vlad from Moscow Avatar answered Jan 02 '23 16:01

Vlad from Moscow


You're right in that, usually, you'd need a forward declaration of such a type:

// Forward declaration
struct bar;

struct foo
{
    bar* d;   // only a pointer-to-bar; forward declaration sufficient
};

struct bar
{
    int c;
};

However, you are (for some reason) using the antiquated idiom of writing struct before the type name. (This was required in C but has never been in C++.)

struct foo
{
    struct bar* d;
};

struct bar
{
    int c;
};

Because you write struct bar there instead of just bar, that itself counts as a forward declaration of sorts. The compiler now knows that bar is a type and that's all it needs to know.

It's a bit obscure and subtle, but that's why you do not need the prior forward declaration any more.

[C++11: 3.1/4]: [ Note: A class name can also be implicitly declared by an elaborated-type-specifier (7.1.6.3). —end note ]

[C++11: 3.3.2/6]: The point of declaration of a class first declared in an elaborated-type-specifier is as follows:

  • for a declaration of the form

       class-key attribute-specifier-seqopt identifier ;

    the identifier is declared to be a class-name in the scope that contains the declaration, otherwise

  • for an elaborated-type-specifier of the form

       class-key identifier

    if the elaborated-type-specifier is used in the decl-specifier-seq or parameter-declaration-clause of a function defined in namespace scope, the identifier is declared as a class-name in the namespace that contains the declaration; otherwise, except as a friend declaration, the identifier is declared in the smallest namespace or block scope that contains the declaration. [ Note: These rules also apply within templates. —end note ] [ Note: Other forms of elaborated-type-specifier do not declare a new name, and therefore must refer to an existing type-name. See 3.4.4 and 7.1.6.3. —end note ]

[C++11: 3.4.4/2]: [..] If the elaborated-type-specifier is introduced by the class-key and this lookup does not find a previously declared type-name, or 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 3.3.2.

like image 40
Lightness Races in Orbit Avatar answered Jan 02 '23 14:01

Lightness Races in Orbit