Требуется ли диагностировать использование неполных типов? - PullRequest
2 голосов
/ 22 апреля 2020

Это языковой адвокат, отвечающий на этот вопрос, где все ответы согласны с тем, что следующее не разрешено :

struct A { A a; };

Есть Несколько случаев, когда могут использоваться неполные типы , внутри самого определения типа, например

struct A { A *a; };
struct A { A &a; };
struct A { std::unique_ptr<A> a; };
struct A { std::vector<A> a; };     // since c++17

et c.

Мой вопрос заключается в том, требуются ли компиляторы для диагностировать программы, которые используют неполные типы способом, который не разрешен? то есть он плохо сформирован? Или у этих программ есть UB? Или что-то еще?

Мне кажется, что некоторые случаи - это просто UB, как пример vector, который компиляторы обычно не диагностируют, даже если это было легализовано только в c ++ 17.

Для пояснения, я спрашиваю только об использовании неполных типов в определении самого типа, как в показанных примерах.

1 Ответ

3 голосов
/ 22 апреля 2020

Это зависит от точного правила. Нарушения большинства правил, связанных с неполными типами классов в разделе основного языка стандарта, должны быть диагностированы. Использование в качестве аргумента шаблона для шаблона стандартной библиотеки является неопределенным поведением, если не указано иное, что дает немного больше возможностей для реализаций.

Эти правила требуют диагностики (так как они указаны с помощью «должны»):

[basi c .def] / 5 :

В определении объекта тип этого объекта не должен быть неполным типом ([basi c .types]), абстрактный тип класса или его (возможно многомерный) массив.

[dcl.fct.def.general] / 2 :

Тип параметра или возвращаемого типа для определения функции не должен быть (возможно, квалифицированным по cv) типом класса, который является неполным или абстрактным в теле функции, если функция не удалена ( [dcl.fct.def.delete]).

[expr.ref] / 4 (относительно типа выражения операнда перед оператором .):

Тип класса должен быть завершен, если не появится доступ к члену класса s в определении этого класса. [ Примечание: Если класс неполный, поиск в полном типе класса необходим для ссылки на то же объявление ([basi c .scope.class]). - конечная нота ]

Поскольку встроенное значение оператора -> определяется с A->B, эквивалентным (*A).B, это также относится к -> операторные выражения.

[class.mem] / 15 :

Тип элемента данных non-stati c не должен быть неполным ([basi c .types]), абстрактный тип класса ([class.abstract]) или его (возможно, многомерный) массив. [ Примечание: В частности, класс C не может содержать нестати c член класса C, но он может содержать указатель или ссылку на объект класса C. - конечная нота ]

[class.derived] / 2 (относительно списка базовых классов для определения класса):

A class-or-decltype должен обозначать (возможно, cv-квалифицированный) тип класса, который не является не полностью определенным классом ([class.mem]); любые cv-квалификаторы игнорируются.

Существуют и другие основные языковые правила, запрещающие неполные типы классов, но наиболее распространенными являются приведенные выше. См. Также ненормативный список контекстов, требующих полного класса в [basi c .def.odr] / 12 .

Я не вижу прямого правила, что qualid-id scope::name неверно сформирован, если scope назовет неполный тип класса, но может просто случиться так, что поиск имени в этом случае обязательно завершится, что является диагностируемым нарушением.

Для Стандартной библиотеки общий запрет на неполные типы в качестве аргументов шаблона составляет [res.on.functions] / (2.5) :

В некоторых случаях (замена функции, функции-обработчики, операции над типами, используемыми для создания экземпляров стандартных шаблонов библиотеки), стандартная библиотека C ++ зависит от компонентов, предоставляемых программой C ++. Если эти компоненты не соответствуют их требованиям, этот документ не предъявляет требований к реализации.

В частности, эффекты не определены в следующих случаях:

  • .. .

  • Если неполный тип ([basi c .types]) используется в качестве аргумента шаблона при создании экземпляра компонента шаблона или оценке концепции, если это специально не разрешено для этого компонента.

Как уже отмечалось, в C ++ 17 добавлено конкретное c разрешение на создание экземпляра класса std::vector<T, Alloc>, но ни один из его членов, если T не является полным и Alloc удовлетворяет «требованиям полноты распределителя» ( [vector.overview] / 4 )

...