инициализатор в виде фигурных скобок или равенства в объединениях

StackOverflow https://stackoverflow.com//questions/23005241

  •  20-12-2019
  •  | 
  •  

Вопрос

Связанный: Как инициализировать не-POD-член в Union

В стандарте говорится

Не более чем один нестатический элемент данных объединения может иметь инициализатор в виде фигурных скобок или равенства.

Но

struct Point {
    Point() {}
    Point(int x, int y): x_(x), y_(y) {}
    int x_, y_;
};

union U {
    int z;
    double w;
    Point p = Point(1,2);
};


#include <iostream>
int main () {
    U u;
    std::cout << u.p.x_ << ":" << u.p.y_ << std::endl;
}

печать 4196960:0 вместо ожидаемого 1:2.

Я считаю это ошибкой компилятора.Это так?

Это было полезно?

Решение

C++11 [class.ctor]/5 состояний:

A по умолчанию конструктор для класса X является конструктором класса X это может быть вызвано без аргумента.Если для класса нет объявленного пользователем конструктора X, конструктор, не имеющий параметров, неявно объявляется как defaulted (8.4).Неявно объявленный конструктор по умолчанию - это inline public представитель своего класса.Установленный по умолчанию конструктор для класса X определяется как удаленный, если:

  • X это класс, подобный объединению, который имеет элемент variant с нетривиальным конструктором по умолчанию,
  • любой нестатический элемент данных без инициализатор с фигурной скобкой или равным значением имеет ссылочный тип,
  • любой невариантный нестатический элемент данных типа const-qualified (или его массива) без инициализатор с фигурной скобкой или равным значением не имеет предоставляемого пользователем конструктора по умолчанию,
  • X является объединением, и все его вариантные члены имеют тип const-qualified (или его массив),
  • X является классом, не являющимся объединением, и все члены любого анонимного члена объединения имеют тип const-qualified (или его массив),
  • любой прямой или виртуальный базовый класс, или нестатический элемент данных без инициализатор с фигурной скобкой или равным значением, имеет тип класса M (или их массив) и либо M не имеет конструктора по умолчанию или разрешения перегрузки (13.3) применительно к Mконструктор по умолчанию приводит к неоднозначности или к функции, которая удалена или недоступна из конструктора по умолчанию, или
  • любой прямой или виртуальный базовый класс или нестатический элемент данных имеет тип с деструктором, который удален или недоступен из конструктора по умолчанию.

Конструктор по умолчанию является тривиальным, если он не предоставляется пользователем и если:

  • его класс не имеет виртуальных функций (10.3) и виртуальных базовых классов (10.1), и
  • ни один нестатический элемент данных своего класса не имеет инициализатор с фигурной скобкой или равным значением, и
  • все прямые базовые классы его класса имеют тривиальные конструкторы по умолчанию, и
  • для всех нестатических элементов данных своего класса, которые относятся к типу class (или его массиву), каждый такой класс имеет тривиальный конструктор по умолчанию.

В противном случае конструктором по умолчанию является нетривиальный.

Поскольку структура Point в OP есть нетривиальный конструктор по умолчанию,

Point() {}

конструктор по умолчанию, используемый по умолчанию для объединения, содержащего элемент типа Point должен быть определено как удаленное в соответствии с первым маркером:

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

в результате программа, представленная в ОП, была неправильно сформирована.

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

В соответствии с пунктом 5 статьи 12.1 [class.ctor],

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

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

  • ...

  • X является объединением, и все его вариантные члены имеют тип const-qualified (или его массив),

  • X является классом, не являющимся объединением, и все члены любого анонимного члена объединения имеют тип const-qualified (или его массив),

  • ...

Поскольку наличие нестатического инициализатора элемента данных является моральным эквивалентом mem-инициализатор, эти правила, вероятно, следует изменить, чтобы не определять сгенерированный конструктор как удаленный, когда член объединения имеет нестатический инициализатор элемента данных.(Обратите внимание на ненормативные ссылки в пунктах 2-3 пункта 9.5 [class.union] и пункте 2 пункта 7.1.6.1 [dcl.type.cv], которые также потребуется обновить, если это ограничение будет изменено.)

Также было бы полезно добавить требование к 9.5 [class.union], требующее либо нестатического инициализатора элемента данных, либо предоставляемого пользователем конструктора, если все члены объединения имеют типы с константной квалификацией.

В более общем плане, почему конструктор по умолчанию определен как удаленный только потому, что у элемента есть нетривиальный конструктор по умолчанию?Само объединение не знает, какой член является активным, и конструкция по умолчанию не будет инициализировать никаких членов (при условии, что нет инициализатор с фигурной скобкой или равным значением).“Владелец” объединения должен контролировать время жизни активного члена (если таковой имеется), и требование наличия предоставляемого пользователем конструктора приводит к созданию шаблона проектирования, который не имеет смысла.Аналогично, почему деструктор по умолчанию определен как удаленный только потому, что у элемента есть нетривиальный деструктор?Я бы согласился с этим ограничением, если бы оно применялось только в том случае, если у объединения также есть предоставляемый пользователем конструктор.

Выпуск 1623 имеет статус "редакционный", что указывает на то, что комитет считает, что проблема, вероятно, является дефектом - зачем еще допускать инициализатор с фигурной скобкой или равным значением для члена профсоюза?- но еще не уделил времени тому, чтобы определить правильную формулировку резолюции.Действительно, этот абзац в основном такой же, как в текущем проекте C++14 N3936 ([class.ctor]/4), за исключением того, что формулировка "любой прямой или виртуальный базовый класс или нестатический элемент данных" везде заменена более простым "любой потенциально сконструированный подобъект".

Хотя поведение обоих компиляторов не является строго соответствующим, я бы счел, что Clang ведет себя в духе стандарта.Может показаться, что GCC приходит в замешательство из-за сочетания удаленного конструктора по умолчанию и инициализатор с фигурной скобкой или равным значением:

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top