Попытка скомпилировать следующий код на разных компиляторах дает мне два разных результата:
struct S{};
struct T{S S;};
int main(){}
Как видите, внутри T
, У меня есть объект, названный так же, как ранее определенный класс S
,
На GCC 4.7.2, Я получаю следующую ошибку относящийся к S S;
декларация внутри T
:
ошибка: объявление ‘S T :: S’ [-fpermissive] ошибка: меняет значение ‘S’ с ‘struct S’ [-fpermissive]
Тем не менее, перемещая его за пределы класса (или в main
) работает отлично:
struct S{};
S S;
int main(){}
Что именно означает ошибка, которую она мне дает?
В Visual Studio 2012 все это компилируется и запускается без ошибок. Вставить его в этот компилятор Clang 3.0 также не дает мне ошибок.
Какой правильный? Могу ли я на самом деле сделать это или нет?
gcc правильный, из [3.3.7 Область действия класса]
Имя N, используемое в классе S, должно ссылаться на то же объявление в его
контекст и при переоценке в завершенном объеме S. Нет
Диагностика необходима для нарушения этого правила.
Тем не менее, обратите внимание, что no diagnostic is required
так что все компиляторы соответствуют.
Причина в том, как работает класс. Когда ты пишешь S S;
S
виден внутри все класс и меняет значение при использовании S
,
struct S{};
struct T{
void foo()
{
S myS; // Not possible anymore because S refers to local S
}
S S;
};
Этот код неверен, диагностика не требуется. Как гласит диагностика, если в объявлении используется имя, а имя имеет другое значение, чем при взгляде в конце определения класса, программа не сформирована, диагностика не требуется.
@JesseGood предоставит полный ответ, но если вы действительно хотите сделать это без ошибок, вы можете использовать полное имя типа, и оно будет работать следующим образом:
struct S {};
struct T { ::S S; };
int main() {return 0;}
Нет, ошибки нет, так как S
в вашем классе T::S
и его тип ::S
!