C++ 在类中引入的类名不会被视为嵌套类名

C++ 在类中引入的类名不会被视为嵌套类名,c++,c++11,g++,C++,C++11,G++,以这些类定义为例: 类别定义1: struct A { struct B* m_b; }; 类别定义2: struct A { struct B; B* m_b; }; 这两个类定义都应该将B声明为嵌套类。至少,通过阅读C++11标准草案中的以下内容,我是这么想的: 9.1/2类声明将类名引入其声明的范围,并将任何类、变量、函数或该名称的其他声明隐藏在封闭范围内(3.3)。如果在一个范围内声明了类名,其中还声明了同名的变量、函数或枚举数,那么当两个声明都在范围内时,只能

以这些类定义为例:

类别定义1:

struct A 
{
   struct B* m_b;
};
类别定义2:

struct A 
{
   struct B;
   B* m_b;
};
这两个类定义都应该将
B
声明为嵌套类。至少,通过阅读C++11标准草案中的以下内容,我是这么想的:

9.1/2类声明将类名引入其声明的范围,并将任何类、变量、函数或该名称的其他声明隐藏在封闭范围内(3.3)。如果在一个范围内声明了类名,其中还声明了同名的变量、函数或枚举数,那么当两个声明都在范围内时,只能使用详细的类型说明符引用该类`

但是,g++4.8.2对它们的处理方式有所不同。在第一个定义中,它将
B
视为与
a
对等的类

以下程序已成功构建:

struct A 
{
   struct B* m_b;
};

void myfun(const B& b )
{
}

int main()
{
   A a;
   myfun(*a.m_b);
}
而以下程序不适用:

struct A 
{
   struct B;
   B* m_b;
};

void myfun(const B& b )
{
}

int main()
{
   A a;
   myfun(*a.m_b);
}
我理解为什么第二个程序没有编译,但我不理解为什么第一个程序成功构建

我在解释标准时是否遗漏了什么


编译第一个程序时g++4.8.2正确吗?

g++在这里的行为完全正确。本标准§3.3.2[基本范围pdecl]/p7中规定了这一点:

类的声明点,在 详细的类型说明符如下所示:

  • 对于表格的声明
    类键属性说明符seqopt标识符
    标识符声明为包含的作用域中的类名 声明,否则
  • 对于格式为
    类键标识符
    如果详细的类型说明符用于 在命名空间范围中定义的函数,标识符声明为 包含声明的命名空间中的类名;否则,除非作为友元声明*,否则将声明标识符 在包含 声明
请注意,在第二种情况下,声明始终放在命名空间或块范围中,而不是类范围中,因此它永远不能声明嵌套类。此外,在第二种情况下,将执行查找,并且仅当未找到以前声明的类型名称时,才会使用详细的类型说明符声明新名称(§3.4.4[basic.lookup.elab]/p2,§9.1[class.name]/p3注)


*朋友声明有自己奇怪的规则。在友元声明中首先声明的名称仍然放在名称空间(对于非本地类)或块(对于本地类)范围中,但它们在包含它们的范围中声明之前,对于大多数名称查找(对于函数,ADL除外)都不可见。§7.3.1.2[名称空间.memdef]/p3中规定了非本地类的规则:

如果非局部类中的友元声明首先声明一个类或函数,则友元类或函数是最内层封闭命名空间的成员。非限定查找(3.4.1)或限定查找(3.4.3)不会找到好友的名称,直到在该命名空间范围中提供匹配声明(在类定义之前或之后)。如果调用友元函数,则可以通过名称查找找到其名称,该名称查找考虑来自名称空间的函数以及与函数参数类型相关联的类(3.4.2)。如果 朋友声明中的名称既不合格也不为模板ID,声明是函数或详细类型说明符,查找以确定实体是否已被声明,不应考虑最内层封闭命名空间以外的任何范围。 本地课程的规则在§11.3[课程名称]/p11中规定:

如果友元声明出现在本地类(9.8)中,并且指定的名称是非限定名称,则会查找先前的声明,而不考虑位于最内层封闭非类范围之外的范围。[…]对于友元类声明,如果没有先前的声明,则指定的类属于最内层的封闭非类范围,但如果随后引用了该类,则在最内层的封闭非类范围中提供匹配声明之前,不会通过名称查找找到其名称


你能从“注意,在第二种情况下……”开始更详细地解释一下你上面写的内容吗?我的理解是,此注释适用于第一个代码,标识符
B
被视为在包含声明的最小命名空间或块范围(即全局命名空间)中声明的类名。对吗?如果是这样的话,这背后的理性是什么?@WakeupBrazil“第二种情况”,如引用标准中的第二个要点,而不是问题中的第二段代码。