c++ - 具有前向声明的嵌套类在 clang++ 中导致错误,但在 g++ 上通过时没有警告
问题描述
我正在尝试结合嵌套类和前向声明以保持代码清晰易读,即使它具有非常复杂的类结构。前向声明允许我在这里减少缩进级别。
以下代码在 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 类中移动类定义,但是假设我想保留这个版本的前向声明。
解决方案
类头名称包含嵌套名称说明符的类说明符可能不会出现在类中;仅在封闭的命名空间内
来自[class]/11:
如果一个类头名称 包含一个嵌套名称说明符,则该类说明符应引用先前直接在 嵌套名称说明符所指的类或命名空间中声明的类,或者在该命名空间的内联命名空间集(即,不仅仅是由using-declaration继承或引入),并且类说明符应出现在包含先前声明的命名空间中。在这种情况下,定义的class-head-name的nested-name-specifier不应以decltype-specifier开头。
在您失败的示例中,A::
是nested-name-specifier并且A::B { ... }
是class-specifier。标准
[...]类说明符应出现在包含先前声明的命名空间中。
没有实现。特别要注意,类说明符包含class-head,而 class-head 又包含一个class-head-name,而 class-head-name 又包含一个可选的嵌套名称说明符,以及(非可选的)一个类-名字。如果存在嵌套名称说明符,则 [class]/11 适用,在这种情况下(如上文所强调的),适用于允许类说明符的位置;特别是,不允许嵌套在一个类中。
因此,您的程序格式错误;叮当是对的。
我们可能会注意到,如果类说明符forB
出现在命名空间范围内(包含先前的类内声明),则 Clang 接受该程序:
class Outer {
public:
class A {
public:
class B;
};
};
class Outer::A::B {
public:
int foo=0;
};
最后,请注意[class.nest]/3提到在声明它们的类的类中定义嵌套类,以及在封闭命名空间的命名空间范围内定义嵌套类:
如果 class
X
在命名空间范围内定义,则嵌套类Y
可以在 class 中声明,然后在 classX
的定义中定义,X
或者稍后在包含 class 定义的命名空间范围内定义X
。[_ 例子:_class E { class I1; // forward declaration of nested class class I2; class I1 { }; // definition of nested class }; class E::I2 { }; // definition of nested class
<em>—结束示例]
这允许您的第一个示例:
class A { public: class B; }; class 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 没有冲突,它专门管理当类头名称包含嵌套名称说明符时允许的语法。
推荐阅读
- makefile - 如何在使用 make 规则的变量提供先决条件的同时处理文件名中的空格?
- react-native - axios 和 android 模拟器的网络错误
- python - 使用相同键将多个字典的值添加到另一个字典的正确方法
- php - 这种类型的路由在 CodeIgniter 中是可能的吗?
- java - C++ 与 Java 记忆差异
- python - 从 GroupBy Frame Pandas 创建字典列表:Python
- c# - 使用第三方库将 windows 项目迁移到 VS 2017
- elasticsearch - Elasticsearch 按嵌套聚合结果过滤
- python - 是否有一个模仿 A[[i,j],...][...,[a,b,c]] 但不是只读的 numpy 函数?
- xml - 春季集成:如何汇总所有新电子邮件并进行计数