Почему std :: vector работает с неполными типами в определениях классов? - PullRequest
7 голосов
/ 10 июля 2019

Возник следующий вопрос:

Стандарт c ++, похоже, говорит, что std::vector требует для работы полный тип. (См. https://en.cppreference.com/w/cpp/container/vector). Почему следующий код все еще компилируется?

#include <vector>

struct parent;

struct child
{
    std::vector<parent> parents; //parent is incomplete here!
};

struct parent
{
    std::vector<child> children;
};

Это кажется нелогичным. Если для std::vector требуется полный тип, то std::vector<parent> не должен компилироваться, поскольку в определении класса child.

известно только его прямое объявление.
  • Является ли это поведение чем-то особенным в определениях классов?
  • Я правильно понял, и std::vector не требуется полный тип?
  • Или это просто случайность? В том, что технически это не разрешено, но в любом случае работает для всех реализаций ...

EDIT

Кажется, есть разница между c ++ 11 и c ++ 17. Я хотел бы понять версию C ++ 11.

1 Ответ

10 голосов
/ 10 июля 2019

Стандарт гласит (черновик N3690; это пост C ++ 11, до C ++ 14):

[res.on.functions]

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

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

- если неполный тип (3.9) используется в качестве аргумента шаблона, когда создание экземпляра шаблона, если специально не разрешено этот компонент.

Учитывая, что стандарт не предъявляет никаких требований, а эффекты не определены (насколько я могу судить, это то же самое, что и неопределенное поведение), инстанцирование не ожидает "не сработает" больше, чем ожидание для него (похоже) на «работу».


Начиная с C ++ 17, требование было смягчено, и std::vector требует , а не требует, чтобы тип значения был завершен, если используется с соответствующим распределителем (соответствующий распределитель по умолчанию). (Эта свобода не распространяется на использование всех функций-членов; у них есть дополнительные требования).

Стандартная цитата (текущий проект):

[vector.overview]

Неполный тип T может использоваться при создании экземпляра вектора, если распределитель удовлетворяет требованиям полноты распределителя. T должен быть завершен до того, как будет получен какой-либо член результирующей специализации вектора.

[allocator.requirements.completeness]

Если X является классом-распределителем для типа T, X дополнительно отвечает требованиям полноты распределителя, если, является ли T полным типом:

  • X - полный тип, а
  • все типы членов allocator_traits, кроме value_type, являются полными типами.

[default.allocator]

Все специализации распределителя по умолчанию соответствуют требованиям полноты распределителя ([allocator.requirements.completeness]).

...