我试图将嵌套类和转发声明结合起来,以保持代码的易读性,即使它有一个非常复杂的类结构。正向声明使我可以减少这里的缩进级别。
下面的代码在g++-9.3和clang++-10上都能很好地编译:
class A {
public:
class B;
};
class A::B {
public:
int foo=0;
};但是,当我在另一个类中执行相同的嵌套操作时,此构造在g++上工作时没有任何警告,但在clang++上失败:
class Outer {
public:
class A {
public:
class B;
};
class A::B {
public:
int foo=0;
};
};clang++失败的原因是:
test.cpp:7:16: error: non-friend class member 'B' cannot have a qualified name
class A::B {
~~~^
1 error generated.我猜这在某种程度上是无效的代码,gcc是仁慈的,能够正确地解释吗?我意识到我可以直接在类A中移动类定义,但是假设我想保留这个带有向前声明的版本。
发布于 2020-11-18 23:38:34
其class-head-name包含嵌套名称说明符的class说明符不能出现在类中;只能出现在封闭的命名空间中
如果类头名称包含使用说明符,则类说明符应引用先前直接在 nested-name-specifier 引用的类或命名空间中声明的类,或者在该命名空间的内联命名空间集合的元素中声明的类(即,不仅仅是由声明继承或引入的),和 class-specifier名称应该出现在包含前一个声明的命名空间中。在这种情况下,定义的类头名称的嵌套名称说明符不能以decltype说明符开头。
在失败的示例中,A::是嵌套名称说明符,A::B { ... }是类说明符。标准
...类说明符应该在包含前一个声明的命名空间中出现为。
没有得到满足。特别要注意的是,class说明符包含class-head,而class-head-name又包含class-head-name,而class-head-name又可选地包含嵌套名称说明符,以及(非可选) class-name。如果存在嵌套名称说明符,则应用class/11,在这种情况下(如上所述),将应用允许在何处使用类说明符的要求;特别是,不允许嵌套在类中。
因此,你的程序是病态的;Clang是正确的。
我们可能会注意到,如果B的类指定符出现在名称空间作用域(包含先前的类内声明),则Clang接受该程序:
class Outer {
public:
class A {
public:
class B;
};
};
class Outer::A::B {
public:
int foo=0;
};最后,请注意,[class.nest]/3提到了在声明嵌套类的类的类中定义嵌套类,以及在封闭命名空间的命名空间范围内定义嵌套类:
如果在命名空间范围中定义类
X,则嵌套类Y可以在类X中声明,稍后在类X的定义中定义,或者稍后在包含类X的定义的命名空间范围中定义。_ Example:_
类E{类I1;//正向声明嵌套类类I2;类I1 { };//定义嵌套类};类E::I2 { };//定义嵌套类
- end示例
这是你的第一个例子:
类A{ public:类B;};类A::B { public: int foo=0;};
被重构为
class A {
public:
class B {
public:
int foo=0;
};
};或
class A {
public:
class B; // forward declaration
// ...
class B {
public:
int foo=0;
};
};但是这里与class/11没有冲突,当class-head-name包含嵌套名称说明符时,class/11专门管理所允许的语法。
发布于 2020-11-18 23:34:32
我认为代码是有效的,这是一个clang bug。根据class.qual#1的说法
如果限定id的嵌套名称说明符指定了一个类,则在类(class.member.lookup) 的作用域中查找在嵌套名称说明符之后指定的名称,下面列出的情况除外。该名称应表示该类或其基类之一(class.derived)的一个或多个成员。
..。
上述名称查找规则的例外情况如下:
(1.1)析构函数的查找如basic.lookup.qual中所指定;
(1.2)转换函数id的转换类型id的查找方式与类成员访问中的转换类型id相同(参见basic.lookup.classref);
(1.3)在整个后缀表达式出现的上下文中查找模板id的模板参数中的名称;
(1.4)查找在使用声明(namespace.udecl)中指定的名称时,还会查找隐藏在同一范围内的类或枚举名称。
所有例外都不适用于A::B的情况。没有要命名的析构函数,没有转换类型id,没有模板,也没有使用声明。
A在作用域中,而B是A的可访问成员,因此查找应该会成功。
https://stackoverflow.com/questions/64895983
复制相似问题