Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Alternative to forward declaration

Tags:

c++

I noticed that prepending the class or struct keyword to a type that would otherwise need be forward declared works as if that type was forward declared:

// struct Test; forward declaration commented

void* foo(struct Test* t) // C style function parameter - This works !
{
    return t; 
}

I wasn't aware of that. I wonder if it's standard C++ or an extension and whether the struct keyword before the parameter works as a forward declaration or another mechanism kicks in.

Furthermore, after such a usage the "next" function can use the type without prepending any keywords :

void* oof(Test* t);

Demo

like image 224
Nikos Athanasiou Avatar asked Jul 29 '15 09:07

Nikos Athanasiou


People also ask

Should I use forward declaration or include?

A forward declaration is much faster to parse than a whole header file that itself may include even more header files. Also, if you change something in the header file for class B, everything including that header will have to be recompiled.

Is forward declaration good practice?

The Google style guide recommends against using forward declarations, and for good reasons: If someone forward declares something from namespace std, then your code exhibits undefined behavior (but will likely work).

Why should I use forward declarations?

A forward declaration allows us to tell the compiler about the existence of an identifier before actually defining the identifier. In the case of functions, this allows us to tell the compiler about the existence of a function before we define the function's body.

Where do you put forward declarations?

Generally you would include forward declarations in a header file and then include that header file in the same way that iostream is included.


1 Answers

This is legal, but probably not a good idea.

From [basic.scope.pdecl]/6:

[...] — 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 [...]

For example:

namespace mine {
    struct T* foo(struct S *);
//  ^^^^^^^^^---------------- decl-specifier-seq
//                ^^^^^^^^^^--- parameter-declaration-clause
}

This introduces T and S as class-names and foo as a function name into namespace mine.


Note that the behavior is different in C; the struct name is only valid within the scope of the function.

6.2.1 Scopes of identifiers

4 - [...] If the declarator or type specifier that declares the identifier appears [...] within the list of parameter declarations in a function definition, the identifier has block scope, which terminates at the end of the associated block. If the declarator or type specifier that declares the identifier appears within the list of parameter declarations in a function prototype (not part of a function definition), the identifier has function prototype scope, which terminates at the end of the function declarator.

gcc gives an appropriate warning for this usage in C code:

a.c:3:18: warning: ‘struct Test’ declared inside parameter list
 void* foo(struct Test* t)
                  ^
a.c:3:18: warning: its scope is only this definition or declaration, which is probably not what you want
like image 177
ecatmur Avatar answered Oct 10 '22 08:10

ecatmur