Спроба зрозуміти шаблони та пошук імен


9

Я намагаюся зрозуміти наступні фрагменти коду

Фрагмент №1

template <typename T>
struct A
{
    static constexpr int VB = T::VD;
};

struct B : A<B>
{
};

Ні gcc9, ні clang9 тут не створюють помилок.

З. Чому цей код складається? Хіба ми не миттєві A<B>при спадкуванні від B? Немає VD в B, тож чи не повинен компілятор викидати тут помилку?

Фрагмент №2

template <typename T>
struct A
{
    static constexpr auto AB = T::AD; // <- No member named AD in B
};

struct B : A<B>
{
    static constexpr auto AD = 0xD;
};

У цьому випадку gcc9 створює штраф, але clang9 видає помилку, кажучи: "Немає учасника з іменем AD в B".

З. Чому він компілюється з gcc9 / чому він не компілюється з clang9?

Фрагмент №3

template <typename T>
struct A
{
    using TB = typename T::TD;
};

struct B : A<B>
{
    using TD = int;
};

Тут і clang9, і gcc9 викликають помилку. gcc9 говорить про "недійсне використання неповного типу" struct B "".

Q. Якщо структура B тут неповна, то чому вона не є неповною у фрагменті №2?

Компілятора прапори використовуються: -std=c++17 -O3 -Wall -Werror. Спасибі заздалегідь!!!


@xception Чи не struct Bінстанцірованія Aз B?
Змінна побічна дія

clang9 видає помилку, кажучи: "Немає учасника з іменем AD в B" . як Bнеповна ... Але не впевнені, коли члена повинні бути
примірковані

@MutableSideEffect о, так, шкода, прочитайте це також як шаблон :(
xception

@ Jarod42, то чому gcc складає штрафи?
Мобільний побічний ефект

1
Я позначив це запитання як "потребує більшої уваги", і питання дійсно містить більше ніж одне запитання (звідси мій висновок), то чому мій прапор неправильний?
Домінік

Відповіді:


4

Я вважаю, що вони по суті зводяться до [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, так і клаксону є коректною інтерпретацією стандарту в даному випадку ...


Дякую. У цьому випадку ми ініціалізуємо статичний член даних у тілі. Чи є частиною декларації ініціалізація, або частиною визначення статичного члена даних? У мене склалося враження, що якщо ініціалізація знаходиться в тілі, то це частина декларації статичного члена даних. Якщо це частина декларації, то ваша перша цитата вимагає негайної інстанції як частини оточуючої неявної інстанції шаблону класу.
Йоханнес Шауб - ліб

Я заглянув у специфікацію, і, здається, тут є різниця між C ++ 14 і C ++ 17. У C ++ 14 constexprстатичний член даних був лише декларацією. C ++ 17 отримав inlineзмінні та constexprозначає inline, що робить декларацію члена статичних даних у тілі визначенням.
Йоханнес Шауб - ліб

eel.is/c++draft/dcl.spec.auto#4.sentence-2 говорить: "Тип змінної, оголошеної за допомогою типу заповнювача, виводиться з її ініціалізатора. Це використання дозволено в ініціалізаційному оголошенні ([dcl. init]) змінної. " Тому я заперечую, що визначення статичного члена даних потрібно, оскільки воно містить ініціалізатор.
Йоханнес Шауб - ліб

@ JohannesSchaub-litb Дякую за те, що вивчив це! Я також цікавився цим питанням, але не зміг знайти жодного формулювання, яке було б переконливим. Щодо речі ініціалізації та визначення, розглянемо визначення функції-члена всередині визначення шаблону класу. Таке визначення також є декларацією і інших декларацій немає. Тим не менш, неявна інстанція шаблону класу буде створювати лише декларацію, але не визначення функції-члена. Чому те ж саме не стосується статичних членів даних?
Майкл Кензель

якщо немає нічого, що вимагає дефінітону, визначення не є миттєвим. Але у autoвипадку правило говорить, що декларація повинна бути ініціалізуючою заявою. Це може бути лише в тому випадку, якщо відомо, що декларація - це визначення (наскільки я знаю .. Я деякий час був поза юристом). У минулому був аналогічний випадок, і eel.is/c++draft/temp.inst#2.sentence-3 додано, де декларація, що це визначення, інстанціюється як "відомо, що це визначення", фактично миттєве визначення.
Йоханнес Шауб - ліб
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.