Следующая программа компилируется без ошибок с помощью 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: error: определение 'void A:: f()' не находится в пространстве имен, в котором содержится 'A' [-fpermissive]
Почему? Это ошибка в GCC?
Если вторая версия программы нарушает правило стандарта С++, какое правило это нарушает и почему MSVS и clang не дают диагностическое сообщение для этого нарушения?
Это случай двусмысленности стандарта С++?
Из сообщения об ошибке похоже, что GCC неправильно считает, что у нас есть нарушение следующего правила:
- http://eel.is/c++draft/class.mfct#2 "Определение функции-члена, которое появляется за пределами определения класса, должно появиться в области пространства имен, охватывающей определение класса."
У нас нет нарушения этого правила, поскольку определение функции-члена находится внутри определения класса. Моя теория состоит в том, что GCC смешивает класс декларации A; в глобальном пространстве имен с классом определения класса A {...} в пространстве имен Y. Я думаю, что у нас есть ошибка в GCC.
С GCC они объявляют одну и ту же сущность. Это можно увидеть, заметив, что в первой версии программы можно использовать:: A как полный тип в основном при компиляции с GCC. То же самое для MSVS. Вместе с Clang они объявляют разные сущности. Эта разница может быть вызвана двусмысленностью в стандарте С++. Независимо от такой двусмысленности мы явно не нарушаем http://eel.is/c++draft/class.mfct#2. Это правило очень ясно.
Связанный вопрос: Объявление класса в той же области, что и с использованием компиляций декларации в GCC, но не MSVS