Нарушает ли он стандарт для неконструктурируемой по умолчанию структуры, в которой отсутствует определяемый пользователем конструктор?

Можно определить struct (а) который не имеет пользовательских конструкторов, и (б) для которого не может быть создан конструктор по умолчанию. Например, Foo ниже:

struct Baz
{
Baz(int) {}
};

struct Foo
{
int bar;
Baz baz;
};

Вы все еще можете создавать экземпляры Foo используя агрегатную инициализацию:

Foo foo = { 0, Baz(0) };

Мой обычный компилятор (VS2012) неохотно примет это, но выдает 2 предупреждения:

предупреждение C4510: «Foo»: конструктор по умолчанию не может быть сгенерирован.

предупреждение C4610: никогда нельзя создавать экземпляр struct ‘Foo’ — требуется определенный пользователем конструктор

Конечно, я только что доказал предупреждение № 2 неправильно — вы все еще можете создать его экземпляр с помощью агрегатной инициализации. Онлайн-компиляторы, которые я попробовал, достаточно счастливы, чтобы принять вышесказанное, поэтому я предполагаю, что VS2012 просто чрезмерно агрессивен с этим предупреждением. Но я хотел бы быть уверен — этот код в порядке, или он технически нарушает какую-то неясную часть стандарта?

6

Решение

Стандарт явно разрешает такие случаи, как Foo в [12.1p4]:

[…] Если нет объявленного пользователем конструктора для
класс X, конструктор без параметров неявно объявляется как дефолтный […] конструктор по умолчанию для класса X определяется как
удалено, если:

[…]
  • любой потенциально сконструированный подобъект, за исключением нестатического члена данных с инициализатором скобок или равных, имеет тип класса M (или массив
    из них) и либо М не имеет конструктора по умолчанию или перегрузка
    разрешение (13.3) применительно к конструктору M по умолчанию приводит к
    неоднозначность или в функции, которая удалена или недоступна из
    конструктор по умолчанию
[…]

Baz не имеет конструктора по умолчанию, поэтому применяется выделенная часть выше (выделено мной).

В таких случаях нет ничего «неопределенного» или «плохо сформированного». Неявно объявленный конструктор по умолчанию определяется как удаленный, вот и все. Вы можете сделать то же самое явно, и это все равно будет так же верно.

Определение для агрегатов находится в [8.5.1p1]. Для C ++ 14 это:

Агрегат — это массив или класс (раздел 9) без предоставления пользователем
конструкторы (12.1), нет частных или защищенных нестатических элементов данных
(Раздел 11), без базовых классов (раздел 10) и без виртуальных функций
(10.3).

Часть «не предоставлено пользователем» позволяет вам использовать = delete для всех конструкторов, которые могут быть неявно объявлены (делая их объявленными пользователем, но не предоставленными пользователем), и класс все равно будет агрегатом, что позволит вам использовать для него агрегатную инициализацию.

Что касается предупреждения C4610, я столкнулся с ним перед собой и сообщил об этом. Как вы можете видеть, это было исправлено в следующей версии VC ++.

Возможно, стоит упомянуть, что пример, который я использовал в отчете об ошибках, взят прямо из стандарта, где он рассматривается как правильно сформированный ([12.2p5.4]:

struct S { int mi; const std::pair<int,int>& mp; };
S a { 1, {2,3} };

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

Конечно, это только пример, но я думаю, что это дополнительный признак того, что в этих случаях нет ничего плохого.

2

Другие решения

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

Агрегаты могут не иметь определяемых пользователем не дефолтных не удаленных конструкторов, и правила для агрегированных UDT состоят в том, что каждый член также должен быть агрегатом. Следовательно, Baz не является совокупностью и, как прямой результат, не может быть Foo.

-1

По вопросам рекламы [email protected]