下面的第一个片段编译,但第二个片段不编译.为什么?

Joã*_*nso 47 c++ declaration definition language-lawyer name-lookup

下面的代码片段编译(演示):

struct A{ int i = 10; };

int main() {
    struct A{ int i = 20; };
    struct A;
    struct A a;
}
Run Code Online (Sandbox Code Playgroud)

但这不是:

struct A{ int i = 10; };

int main() {
//    struct A{ int i = 20; };
    struct A;
    struct A a;
}
Run Code Online (Sandbox Code Playgroud)

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

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

但我真的不知道如何从这两段中推断出上面显示的不同行为.

需要注意的是在第一个例子中,struct A不是第一次在声明阐述类型说明符 struct A;,但在定义struct Amain().

在第二个例子中,struct A先在声明阐述型说明符 struct A;,但在定义struct A在全局范围.

Okt*_*ist 67

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

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

struct A{ int i = 10; };

int main() {
    struct B{ int i = 20; };
    struct B;
    struct B b;
}
Run Code Online (Sandbox Code Playgroud)

以上内容与您的第一个示例在语义上相同.该课程A从未使用过.

struct A{ int i = 10; };

int main() {
    struct B;
    struct B b;
}
Run Code Online (Sandbox Code Playgroud)

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

重命名BA不会改变任何东西,因为Amain阴影中声明了另一个A在全局范围内的声明.

[basic.lookup.elab]/2

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

class-key attribute-specifier-seq选择 identifier ;

阐述了式说明符是引入了一个声明类名如[basic.scope.pdecl]中描述.

struct A;是一个声明,它在声明的范围内引入了类名.在任何情况下,它都不能引用在外部范围内声明的类.

[basic.scope.pdecl]/7

[ 注:其他形式的详细类型说明符不会声明新名称[...] - 尾注 ]

通过暗示,这种形式的详细类型说明符声明了一个新名称.


Fra*_*eux 44

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

struct A{ int i = 10; };

int main() {
//    struct A{ int i = 20; };
    struct A;
    struct ::A a;
}
Run Code Online (Sandbox Code Playgroud)

  • 我明确提到这是一个_forward declaration_. (4认同)
  • @FrançoisAndrieux:我不认为它是一种"疏忽".您的原始版本在技术上是正确的(`struct A;`是声明,但不是定义).但是,编写"前向声明"而非"声明"确实使得非语言律师的答案更容易理解. (2认同)

小智 5

它不能编译,因为它找不到A的定义.

int main() {
//    struct A{ int i = 20; };
      struct A;
      struct A a;
}
Run Code Online (Sandbox Code Playgroud)

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