Подтвердить что ты не робот

Вложенные подклассы в С++

Я пытаюсь создать вложенный класс, который также является подклассом его родителя:

struct X { struct Y : public X {}; };

К сожалению, это, похоже, не разрешено в С++, так как g++ создает ошибку

error: недопустимое использование неполного типа 'struct X'

Однако мой фактический код имеет X в качестве шаблона:

template<typename T> struct X
{ struct Y : public X {}; };

Я получаю одно и то же сообщение, но на этот раз это только предупреждение:

предупреждение: недопустимое использование неполного типа 'struct X <T> '

Мой вопрос: почему первый случай является незаконным, в то время как шаблонный случай просто дает предупреждение? Шаблонная версия работает точно так, как я ожидал бы (я могу создавать экземпляры X<T>::Y, отбрасывать их на X<T> и т.д.), Но означает ли это предупреждение, что я не должен его использовать? С какими проблемами я могу столкнуться, если игнорировать предупреждение?

4b9b3361

Ответ 1

Технически, что касается компилятора, макет базы (X) не требуется знать до тех пор, пока не будет создан шаблон (X). И шаблон (X) не может быть удален до того, как он будет полностью определен. В этот момент известна его компоновка.

Самый простой способ получить сообщение об ошибке из вашего шаблона - попробовать istantiate Y внутри X:

template<typename T> struct X {
    struct Y : public X {};
    Y y;
};

В более ранних версиях компилятора не было предупреждения в том случае, если вы показываете, но в какой-то момент он был добавлен. Вот обсуждение из Gug bugtracker о том, является ли предупреждение ложным. Была некоторая неопределенность относительно того, разрешено ли это стандартом, но их вывод заключался в том, что это не разрешено.

Таким образом, ни один случай не допускается стандартом, но GCC продолжает работать с последним, потому что он может.

Yam Marcovic Показывает, как X::Y можно определить стандартным образом. Аналогично аналогичный пример показан в gcc bugtracker.

Ответ 2

Чтобы ответить на основной вопрос: вы получите предупреждение, потому что шаблон еще не создан, поэтому он никого не беспокоит.

Способ исправить это, в обоих случаях, заключался бы в определении X::Y в точке, в которой макет X уже известен, и, таким образом, макет Y может быть правильно выведен. Вы можете сделать:

struct X { struct Y; }
struct X::Y {};