Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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-seqoptidentifier ;

         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.

like image 646
Ayrosa Avatar asked Mar 18 '19 18:03

Ayrosa


2 Answers

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.

Simply:

namespace ns {
    // declares S into ns as per [basic.scope.pdecl]
    void f(struct S&);
}

extern ns::S s;
//extern ::S s; // not declared

Here struct S is first declared in the elaborated-type-specifier in a parameter-declaration-clause of a function defined in namespace scope, with the form class-key identifier, and therefore [basic.scope.pdecl]/7.2 applies and struct S is declared in the namespace ns where the function is declared.

you'll have to use an object of class S in your function f

Here is an example:

// ... continuing from previous example ...
namespace ns {
    struct S {
        int i;
    };

    void f(S& s) {
        std::cout << s.i;
    }
}

As a bonus, an example where the class is not first declared in the elaborated-type-specifier, and so the quoted rule does not apply:

struct S;
namespace ns {
    void f(struct S&); // refers to ::S
}

//extern ns::S s; // not declared
extern ::S s;

Here, the elaborated-type-specifier is not the first declaration of struct S, so [basic.scope.pdecl]/7 does not apply, and no class is declared into the namespace.

like image 30
eerorika Avatar answered Sep 29 '22 11:09

eerorika


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
like image 84
Rakete1111 Avatar answered Sep 29 '22 10:09

Rakete1111