下面的第一个片段编译,但第二个片段没有编译。为什么?

时间:2017-01-04 19:05:28

标签: c++ language-lawyer declaration definition name-lookup

下面的代码段编译(demo):

struct A{ int i = 10; };

int main() {
    struct A{ int i = 20; };
    struct A;
    struct A a;
}

但这并不是:

struct A{ int i = 10; };

int main() {
//    struct A{ int i = 20; };
    struct A;
    struct A a;
}

我可以看到答案可能是标准中的这些段落:

[basic.lookup.elab]/2[basic.scope.pdecl]/7

但我真的不知道如何从这两段中推断出上述不同的行为。

请注意,在第一个示例中,struct A首先在 elaborated-type-specifier struct A;中声明 ,但在定义中struct A中的main()

在第二个示例中,struct A elaborated-type-specifier struct A;中首次声明 ,但在定义中struct A在全球范围内。

3 个答案:

答案 0 :(得分:67)

每个示例都包含两个不同类的声明,两个名称都为A

让我们通过将其中一个重命名为B来区分类:

struct A{ int i = 10; };

int main() {
    struct B{ int i = 20; };
    struct B;
    struct B b;
}

以上内容与您的第一个示例在语义上相同。从未使用过类A

struct A{ int i = 10; };

int main() {
    struct B;
    struct B b;
}

这在语义上与第二个示例相同。您正在尝试创建一个不完整类型的对象,即前向声明的类B

B重命名为A不会改变任何内容,因为Amain的声明会影响全球另一个A的声明范围。

<强> [basic.lookup.elab] / 2

  

如果 elaborated-type-specifier 没有嵌套名称说明符,并且[...]如果 elaborated-type-specifier 出现在声明中,格式为:

     
    

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

  
      elaborated-type-specifier 是一个声明,它引入了 class-name ,如[basic.scope.pdecl]中所述。

因此;声明在声明范围内引入类名称。在任何情况下都不能引用在外部范围内声明的类。

<强> [basic.scope.pdecl] / 7

  

[注意:其他形式的 elaborated-type-specifier 不会声明新名称[...] - 结束注释]

暗示,这种形式的 elaborated-type-specifier 声明了一个新名称。

答案 1 :(得分:44)

在第二个示例中,行struct A;是主函数范围内名为A的结构的前向声明。此结构将优先于全局struct A。下一行定义了一个名为a的{​​{1}}类型的变量。由于在main函数的作用域中声明了struct A,因此编译器将在那里搜索它的定义。它没有找到一个(它被注释掉了)。第一个示例编译,因为在同一范围内有定义。但是,以下示例将编译,因为它指定struct A位于全局命名空间中:

A

答案 2 :(得分:5)

它无法编译,因为它无法找到A的定义。

int main() {
//    struct A{ int i = 20; };
      struct A;
      struct A a;
}

上面的代码等于你的第一个例子,因为全局A被本地A遮蔽。在第二个例子中,A没有定义。这只是一个原型。原型应该放在需要定义的代码之前,当定义放在需要它的代码之后。 如果编译器找不到该定义,它将失败,因为它不知道A应该是什么(全局定义被本地原型遮蔽,导致它被忽略)。