【发布时间】:2015-09-22 19:02:36
【问题描述】:
使用 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 。这条规则很明确。
相关问题:Class declaration in same scope as using declaration compiles in GCC but not MSVS
【问题讨论】:
-
我们必须猜测错误信息是什么吗?
-
我已编辑问题以包含错误消息。我在这里运行它:melpon.org/wandbox/permlink/W3284yJiSuXuahQu
-
就个人而言,在我看来代码不正确-您在类外转发声明
A,然后在类中定义它;如果没有 using 语句,它们将是两个单独的类(即class A和class Y::A,但是使用 using 语句,您已经在class Y的范围内拥有名称A,因此随后定义了 @ 987654332@ 在该范围内看起来应该隐藏该导入的名称(并因此编译)或被视为它的定义,在这种情况下它是违反你发布的那个规则(好吧,至少如果你删除了“函数”这个词)。
标签: c++ gcc language-lawyer using-declaration