我在理解[basic.scope.pdecl] / 7

时间:2019-03-18 18:00:23

标签: c++ language-lawyer forward-declaration

[basic.scope.pdecl]/7

  

第一个类中声明的类的声明点   修饰类型说明符如下:

     

(7.1)用于声明表格

     

class-key attribute-specifier-seq opt identifier {{ 1}}

     

标识符 在包含声明的范围中声明为类名,否则

     

(7.2)格式的修饰型说明符      

类密钥 标识符

     

如果 decl-specifier-seq 中使用了精制类型说明符   或
  名称空间中定义的函数的 parameter-declaration-clause   范围,标识符为   在名称空间中声明为 class-name   包含声明;除此以外,   除了作为朋友   声明,标识符在最小的命名空间中声明,或者   块   包含声明的作用域。 [注意:这些规则也   在模板内应用。 - 结束   注意] [注意:    elaborated-type-specifier 不声明新名称,并且   因此必须引用现有的 type-name 。请参阅[basic.lookup.elab]和   [dcl.type.elab]。   —尾注]

请考虑上述情况(7.2),其中在 parameter-declaration-clause-clause的 decl-specifier-seq 中使用精化类型说明符 在命名空间范围内定义的函数。这个 elaborated-type-specifier 必须是其命名空间中该类的 first 声明这一事实如何与之相提并论?

请考虑以下示例(demo):

文件;

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); }

other.cc

请注意,上面的代码可以正确编译并执行,但是函数#include<iostream> struct S{ int i = 1; }; void f(struct S& s) { std::cout << s.i << '\n'; } S s; parameter-declaration-clause 中的精心设计的类型全局命名空间中的第一个。

假设我对[basic.scope.pdecl] / 7的解释是正确的,我想看看一个示例,该示例显示了上面第(7.2)款的应用,其中所引用的声明是第一在其命名空间中

2 个答案:

答案 0 :(得分:4)

  

如果我们消除了顶部的第一个声明struct S;,则代码不会编译!

那是因为使用它之前,您仍然需要声明一个名称。

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);
}
  

请注意,上面的代码可以正确编译并执行,但是函数f parameter-declaration-clause 中的精心设计的类型全局命名空间中的第一个。

我不明白您要在这里提出的重点。由于不是第一个,所以没有声明任何名称,并且[basic.scope.pdecl] p7不适用。

  

我想看一个示例,显示上面第(7.2)段的应用,其中所引用的声明将是其命名空间中的第一个声明。

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

答案 1 :(得分:3)

  

我想看一个示例,显示上面第(7.2)段的应用,其中所引用的声明将是其命名空间中的第一个声明。

简单地:

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

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

此处struct S首先在命名空间范围内定义的函数的参数声明子句的精细类型说明符中声明,形式为class-key identifier,因此是[basic.scope。 pdecl] /7.2适用,并且struct S在声明函数的名称空间ns中声明。

  

您必须在函数S中使用类f的对象

这里是example

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

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

作为奖励,有一个示例,其中该类没有首先在elaborated-type-specifier中声明,因此引用的规则不适用:

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

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

在这里,elaborated-type-specifier不是struct S的第一个声明,因此[basic.scope.pdecl] / 7不适用,并且没有任何类声明到名称空间中。