以下程序使用 MSVS、clang 和 GCC 编译时没有错误:
class A;
namespace Y {
using ::A;
class A {};
}
int main() {}
现在让我们定义一个成员函数。现在它仍然可以使用 MSVS 和 clang 编译,但不能使用 GCC:
class A;
namespace Y {
using ::A;
class A { void f() {} };
}
int main() {}
GCC 给出以下错误消息:
- prog.cc:5:22:错误:“void A::f()”的定义不在包含“A”的命名空间中 [-fpermissive]
这是为什么?这是 GCC 中的错误吗?
如果程序的第二个版本违反了 c++ 标准的规则,它违反了什么规则,为什么 MSVS 和 clang 不针对该违反给出诊断消息?
这是 c++ 标准模棱两可的情况吗?
从错误消息看来,GCC 错误地认为我们违反了以下规则:
- http://eel.is/c++draft/class.mfct#2 “出现在类定义之外的成员函数定义应出现在包含类定义的命名空间范围内。”
我们没有违反此规则,因为成员函数定义在类定义中。我的理论是 GCC 混淆了声明类 A;在全局命名空间中,类定义 class A { ... } 在命名空间 Y 中。我认为我们在 GCC 中有一个错误。
使用 GCC,他们声明了相同的实体。这可以通过观察在程序的第一个版本中使用 GCC 编译时在 main 中使用 ::A 作为完整类型来看出。MSVS 也一样。然而,对于 Clang,它们声明了不同的实体。这种差异可能是由于 c++ 标准中的歧义。不管这样的模棱两可,我们显然没有违反http://eel.is/c++draft/class.mfct#2。这条规则非常明确。