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

时间:2014-06-26 06:08:34

标签: 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)。如果在声明了同名变量,函数或枚举数的作用域中声明了类名,那么当两个声明都在作用域中时,只能使用 elaborated-type-specifier引用该类。 `

但是,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是否正确?

1 个答案:

答案 0 :(得分:15)

这里的g ++行为是完全正确的。这在标准的§3.3.2[basic.scope.pdecl] / p7中指定:

  

首先在一个声明中声明一个类的声明    elaborated-type-specifier 如下:

     
      
  • 表格形式的声明
       class-key attribute-specifier-seq opt 标识符;
    该标识符在范围内被声明为类名包含   声明,否则
  •   
  • 表示形式为 elaborated-type-specifier    class-key identifier
    如果在 decl-specifier-seq 参数中使用 elaborated-type-specifier -declaration-clause   在命名空间范围内定义的函数,标识符声明为   包含声明的命名空间中的 class-name ;否则,除了作为朋友声明 * 之外,声明标识符   在包含的最小命名空间或块范围内   声明。
  •   

请注意,在第二种情况下,声明始终放在命名空间或块范围内,而不是类范围,因此它永远不能声明嵌套类。此外,在第二种情况下,将执行查找,并且仅当未找到先前声明的类型名称时,才会采用详细类型说明符来声明新名称(§3.4.4[basic.lookup.elab] / p2,§9.1[class.name] / p3 note)。


* 朋友声明有他们自己奇怪的规则。在友元声明中首先声明的名称仍然放在命名空间(对于非本地类)或块(对于本地类)作用域中,但是对于大多数名称查找(在函数的情况下除了ADL)它们都不可见,直到它们为止也在包含它们的范围内声明。非本地类的规则在§7.3.1.2[namespace.memdef] / p3中指定:

  

如果非本地类中的友元声明首先声明一个类或函数,那么友元类或函数是最内层封闭命名空间的成员。在非命名查找(3.4.1)或限定查找(3.4.3)之前找不到朋友的名称,直到在该命名空间范围内提供匹配声明(在授予友谊的类定义之前或之后)。如果调用了友元函数,则可以通过名称查找找到其名称,该名称查找考虑名称空间中的函数和与函数参数类型相关联的类(3.4.2)。如果   朋友声明中的名称既不是合格的也不是 template-id ,声明是函数或 elaborated-type-specifier ,查找以确定实体是否已被先前声明的不应考虑最内层封闭命名空间之外的任何范围。

本地类的规则在§11.3[class.friend] / p11中指定:

  

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