次のプログラムは、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 のバグですか?
プログラムの 2 番目のバージョンが C++ 標準の規則に違反している場合、どの規則に違反していて、MSVS と clang がその違反の診断メッセージを表示しないのはなぜですか?
これは、c++ 標準のあいまいさのケースですか?
エラー メッセージから、次のルールに違反していると GCC が誤って認識しているように見えます。
- http://eel.is/c++draft/class.mfct#2「クラス定義の外に現れるメンバー関数定義は、クラス定義を囲む名前空間スコープに現れるものとします。」
メンバー関数の定義はクラス定義内にあるため、この規則に違反することはありません。私の理論では、GCC はクラス A の宣言を混乱させます。クラス定義 class A { ... } を名前空間 Y に持つグローバル名前空間で、GCC にバグがあると思います。
GCC では、同じエンティティを宣言します。これは、プログラムの最初のバージョンでは、GCC でコンパイルするときに ::A を main の完全な型として使用できることを観察することで確認できます。MSVS も同様です。ただし、Clang では、異なるエンティティを宣言します。この違いは、c++ 標準のあいまいさが原因である可能性があります。このようなあいまいさにもかかわらず、私たちは明らかにhttp://eel.is/c++draft/class.mfct#2に違反していません。そのルールは非常に明確です。
関連する質問:宣言を使用する場合と同じスコープ内のクラス宣言は、GCC ではコンパイルされますが、MSVS ではコンパイルされません