Я считаю, что это сводится к [temp.inst] / 2 (выделено мое):
Неявная реализация специализации шаблона класса вызывает неявную реализацию объявлений, но не определений , аргументов по умолчанию или спецификаторов noexcept для функций-членов класса, классов-членов, перечислений членов-областей, статических членов-данных , шаблонов-членов и друзья; [...]
и [temp.inst] / 9
Реализация не должна неявно создавать экземпляр […] статического члена данных шаблона класса […], если только такое создание не требуется.
Формулировка в стандарте, касающаяся неявного создания шаблона, оставляет много деталей открытыми для интерпретации. В общем, мне кажется, что вы просто не можете полагаться на части шаблона не создаются, если в спецификации указано иное. Таким образом:
Фрагмент №1
В. Почему этот код компилируется? Разве мы не создаем экземпляр A при наследовании от B? В B нет VD, поэтому не должен ли компилятор выдать ошибку здесь?
Вы создаете экземпляр A<B>. Но создание экземпляров A<B>только создает экземпляры объявлений, а не определения его статических элементов данных.VBникогда не используется таким способом, который потребовал бы определения для существования. Компилятор должен принять этот код.
Фрагмент № 2
В. Почему он компилируется с gcc9 / почему не компилируется с clang9?
Как указал Jarod42, декларация AB содержит тип заполнителя. Мне кажется, что формулировка стандарта не совсем ясна в отношении того, что здесь должно происходить. Вызывает ли создание объявления статического члена данных, содержащего тип заполнителя, вычет типа заполнителя и, таким образом, представляет собой использование, которое требует определения статического члена данных? Я не могу найти в стандарте формулировку, которая бы четко говорила «да» или «нет». Таким образом, я бы сказал, что обе интерпретации здесь одинаково действительны, и, таким образом, GCC и Clang оба являются правильными ...
Фрагмент № 3
В. Если структура B здесь неполная, то почему она не неполная во фрагменте № 2?
Классовый тип является полным только в том месте , где вы достигнете закрытия }этого класса спецификатора [class.mem] / 6 . Таким образом, Bнеполный во время неявной реализации A<B>во всех ваших фрагментах. Просто это было неважно для Сниппета № 1. В Snippet # 2 в результате clang выдал ошибку No member named AD in B. Как и в случае с Snippet # 2, я не могу найти формулировку, когда именно будут созданы объявления псевдонимов членов. Однако, в отличие от определения статических членов-данных, не существует формулировок, которые бы явно предотвращали создание деклараций псевдонимов членов во время неявной реализации шаблона класса. Таким образом, я бы сказал, что поведение как GCC, так и Clang является действительной интерпретацией стандарта в этом случае ...
struct BинстанцированииAсB?