Неявно определенный конструктор удален из-за варианта элемента N3690 / N4140 против N4659 / N4727 - PullRequest
0 голосов
/ 15 ноября 2018

Моя история начинается так же, как этот человек здесь:

Объединения в C ++ 11: конструктор по умолчанию, кажется, удален

Разрешение здесь (сейчас около трех лет) немного неудовлетворительно, потому что «копание в стандарте», которое автор сделал, привело к выводу, что поведение было таким, как описано в стандарте, но, к сожалению, цитата из Примечание , и они должны быть ненормативными (мне сказали). В любом случае, есть ссылка на старый отчет об ошибках в gcc, который, как утверждается, исправлен, и они также утверждают, что код компилируется в clang, однако у меня возникают проблемы (с таким же и похожим кодом). Вопрос сводится к тому, должен ли подобный объединению класс с инициализированным по умолчанию вариантом члена-члена компилироваться независимо от того, существует ли другой вариант-член (в том же наборе вариантов), который имеет нетривиальный конструктор.

struct X {
  X() {}        //non-trivial default constructor
};

struct U {
  union {
    X x;
    int i{0};   //default member initializer
  };
};

U u;            //error: default constructor deleted

Это не удалось с -std=c++14 и -std=c++17 на gcc version 7.3.0 (Ubuntu 7.3.0-27ubuntu1~18.04), а также clang version 6.0.0-1ubuntu2.

Кажется, в стандарте есть история изменений, и поэтому я изложу то, что нашел:

N3690 / N4140:
[12.1.4 / Конструкторы] ... Конструктор по умолчанию для класса X определяется как удаленный, если:

  • X является объединяющим классом, в котором есть вариантный член с нетривиальным конструктором по умолчанию

[9.5.2 / Союзы] ... [Заметка: Если какой-либо элемент нестатических данных объединения имеет нетривиальное значение по умолчанию конструктор (12.1), конструктор копирования (12.8), конструктор перемещения (12.8), оператор назначения копирования (12.8), перемещение оператор присваивания (12.8) или деструктор (12.4), соответствующая функция-член объединения должна быть предоставленный пользователем или он будет неявно удален (8.4.3) для объединения. - конец примечания]


N4659 / N4727:
[15.1.5 / Конструкторы] ... Конструктор по умолчанию для класса X определяется как удаленный, если:

  • X - это объединение, в котором есть вариантный член с нетривиальным конструктором по умолчанию, и ни у одного вариантного члена X нет инициализатора элемента по умолчанию

[12.3.3 / Союзы] ... [Заметка: Отсутствуют инициализаторы членов по умолчанию, если любой нестатический член данных объединения имеет нетривиальное значение по умолчанию конструктор (12.1), конструктор копирования (12.8), конструктор перемещения (12.8), оператор назначения копирования (12.8), перемещение оператор присваивания (12.8) или деструктор (12.4), соответствующая функция-член объединения должна быть предоставленный пользователем или он будет неявно удален (8.4.3) для объединения. - конец примечания]


В любом случае, кажется, что в какой-то момент этот код должен был потерпеть неудачу, но считалось, что он соответствует и что у gcc есть ошибка, и она была исправлена, но теперь она должна быть успешной, и это не так компилировать (у меня может не быть идеальной хронологии, было бы интересно узнать всю историю; выяснить это на шаг дальше, чем я хотел бы сделать), но я думаю, мне просто интересно, каково правильное поведение?

1 Ответ

0 голосов
/ 15 ноября 2018

Я верю, что вы правы, теперь это должен быть правильный код.

Оригинальная формулировка ненормативной записки, которая описывает старое поведение, взята из n2544: Неограниченные союзы (Редакция 2) .

Это изменение, замеченное вами в нормативном разделе, исходит из Отчет о дефекте ядра 2048: NSDMI и удаленные конструкторы объединения по умолчанию , в котором говорится:

Согласно15.1 [class.ctor] параграф 4 гласит:

По умолчанию конструктор по умолчанию для класса X определяется как удаленный, если:

  • X подобен объединениюкласс, имеющий вариантный член с нетривиальным конструктором по умолчанию,

  • ...

Это должно привести к следующему примеруплохо сформирован:

  struct S {
    S();
  };
  union U {
    S s{};
  } u;

, потому что конструктор U по умолчанию удален.Однако и clang, и g ++ принимают это без ошибок.Следует ли смягчить правило для объединения с NSDMI?

и изменить [class.default.ctor] p2 , как вы указали в N4659/N4727.Кроме того, мы можем видеть, что случай, упомянутый в DR, действительно работает для gcc и clang, но не для MSVC увидеть его в прямом эфире на godbolt .

Это похоже на ошибку, так как [class.default.ctor] p2.1 должен охватить этот случай и сделать его сформированным, поскольку элемент i имеет инициализатор элемента по умолчанию:

X - это объединение, которое имеетвариантный член с нетривиальным конструктором по умолчанию и без вариантного члена X имеет инициализатор элемента по умолчанию,

...