Следующая программа компилируется без ошибок с 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 они объявляют одну и ту же сущность. Это можно увидеть, заметив, что в первой версии программы можно было использовать :: A как полный тип в main при компиляции с GCC. То же самое и для MSVS. Однако с помощью Clang они объявляют разные сущности. Это различие может быть связано с неоднозначностью стандарта C ++. Несмотря на такую двусмысленность, мы явно не нарушаем http://eel.is/c++draft/class.mfct#2. Это правило очень четкое.
Связанный вопрос: Класс объявление в той же области, что и использование объявления, компилируется в GCC, но не в MSVS
A
вне класса, а затем определяете его в классе; без оператора using это были бы два отдельных класса (т.е.class A
иclass Y::A
, но с оператором using у вас уже есть имяA
в областиclass Y
, поэтому последующее определениеclass A
в этой области выглядит так, как будто оно должно либо скрыть это импортированное имя (и, таким образом, скомпилировать) или использоваться в качестве определения для него, и в этом случае это является нарушением того правила, которое вы опубликовали (ну, по крайней мере, < i> если вы удалите слово функция). - person celticminstrel   schedule 06.07.2015