Search code examples
c++language-lawyerforward-declaration

I'm having some difficulty understanding [basic.scope.pdecl]/7


[basic.scope.pdecl]/7:

The point of declaration of a class first declared in an elaborated-type-specifier is as follows:

(7.1)   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

(7.2)   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 [basic.lookup.elab] and          [dcl.type.elab].— end note ]

Consider the case (7.2) above where the elaborated-type-specifier is used in the decl-specifier-seq of a parameter-declaration-clause of a function defined in namespace scope. How would that conciliate with the fact that this elaborated-type-specifier must be the first declaration of the class in its namespace?

Consider the example (demo) below:

File prog.cc:

struct S;
extern S s;
int S;
void f(struct S&);     // The elaborated-type-specififer `struct S` is not
                       // the first declaration in the global namespace and
                       // if we eliminate the first declaration `struct S;` 
                       // on the top, the code doesn't compile !!
int main(){
    f(s);
}

File other.cc:

#include<iostream>
struct S{
    int i = 1;
};
void f(struct S& s) { std::cout << s.i << '\n'; }
S s;

Note that the code above compiles and executes correctly, but the elaborated-type-specififer in the parameter-declaration-clause of function f is not the first in the global namespace.

Assuming that my interpretation about [basic.scope.pdecl]/7 is correct, I would like to see an example showing the application of paragraph (7.2) above, where the alluded declaration would be the first in its namespace.


Solution

  • if we eliminate the first declaration struct S; on the top, the code doesn't compile !!

    Well that's because you still need to declare a name before you use it.

    int S;
    void f(struct S&); 
    extern struct S s; // If you write this line before then it
                       // will not compile.
                       // The name still needs to be declared
                       // before you use it.
    // If you drop the `int S` above, then the following
    // will also compile, since S has already been declared
    // extern S s2;
    
    int main(){
        f(s);
    }
    

    Note that the code above compiles and executes correctly, but the elaborated-type-specififer in the parameter-declaration-clause of function f is not the first in the global namespace.

    I don't understand the point you're trying to make here. Since it's not the first, no name is declared and [basic.scope.pdecl]p7 doesn't apply.

    I would like to see an example showing the application of paragraph (7.2) above, where the alluded declaration would be the first in its namespace.

    auto addrof(struct S& s) { // First declaration
        return &s;
    }
    int get(struct T&); // First declaration