Я вважаю, що вони по суті зводяться до [temp.inst] / 2 (акцент мій):
Неявна конкретизація шаблону класу спеціалізації викликає неявні створення примірників декларацій, але не з визначень , по замовчуванням аргументів або noexcept специфікаторів цих функцій - членів класу, класів членів, контекстні перерахувань членів, статичних членів даних , шаблонів членів, і друзі; […]
та [temp.inst] / 9
Реалізація не повинна неявно інстанціювати […] статичний член даних шаблону класу […], якщо не потрібна така інстанція.
Формулювання стандарту щодо неявного опису шаблону залишає багато деталей відкритими для тлумачення. Взагалі, мені здається, що ви просто не можете розраховувати на те, що частини шаблону не є екземплярами, якщо специфікація прямо не говорить про це. Таким чином:
Фрагмент №1
З. Чому цей код складається? Хіба ми не створили А при спадкуванні від Б? Немає VD в B, тож чи не повинен компілятор викидати тут помилку?
Ви створюєте інстанцію A<B>
. Але інстанція A<B>
лише створює декларації, а не визначення її статичних даних. VB
ніколи не використовується таким чином, щоб вимагати існування визначення. Компілятор повинен прийняти цей код.
Фрагмент №2
З. Чому він компілюється з gcc9 / чому він не компілюється з clang9?
Як вказував Jarod42, декларація AB
містить тип заповнювача. Мені здалося б, формулювання стандарту не дуже зрозуміло, що має відбуватися тут. Чи є екземпляр декларації статичного члена даних, який містить тип заповнення, викликає виведення типу заповнювача заповнення і, таким чином, являє собою використання, яке вимагає визначення статичного члена даних? Я не можу знайти в стандарті формулювання, яке чітко сказало б так чи ні. Таким чином, я б сказав, що обидві інтерпретації тут однаково справедливі, і, таким чином, GCC і кланг мають обоє права ...
Фрагмент №3
Q. Якщо структура B тут неповна, то чому вона не є неповною у фрагменті №2?
Класовий тип є повним тільки в тому місці , де ви досягнете закриття }
цього класу специфікатор [class.mem] / 6 . Таким чином, B
є неповним під час неявної інстанції A<B>
у всіх ваших фрагментах. Просто це було нерелевантно для знімка №1. У фрагменті №2, кланг зробив вам помилку No member named AD in B
в результаті. Як і у випадку з фрагментом №2, я не можу знайти формулювання про те, коли саме декларації псевдонімів членів будуть екземплярами. Однак, на відміну від визначення статичних членів даних, не існує жодних формулювань, які б явно запобігали інстанціюванню декларацій псевдонімів членів під час неявної інстанції шаблону класу. Таким чином, я б сказав, що поведінка як GCC, так і клаксону є коректною інтерпретацією стандарту в даному випадку ...
struct B
інстанцірованіяA
зB
?