Подтвердить что ты не робот

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

Когда я запускаю этот код:

struct X {
    int a;
};

struct Y : public X {};

X x = {0};
Y Y = {0};

Я получаю:

error: could not convert ‘{0}’ from ‘<brace-enclosed initializer list>’ to ‘Y’

Почему инициализация скобки работает для базового класса, но не для производного класса?

4b9b3361

Ответ 1

Ваша проблема связана с агрегатной инициализацией: struct X - это совокупность, а struct Y - нет. Вот стандартная цитата об агрегатах (8.5.1):

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

В этом предложении указано, что если a class имеет базовый класс, то он не является агрегатом. Здесь struct Y имеет struct X как базовый класс и, следовательно, не может быть агрегатным типом.

Относительно конкретной проблемы, которую вы имеете, сделайте следующее предложение из стандарта:

Когда агрегат инициализируется списком инициализатора, как указано в 8.5.4, элементы списка инициализаторов берутся как инициализаторы для членов агрегата, увеличивая индекс или порядок членов. Каждый член инициализируется копией из соответствующего предложения инициализатора. Если выражение initializer-выражение является выражением, и для преобразования выражения требуется сужающее преобразование (8.5.4), программа плохо сформирована.

Когда вы выполняете X x = {0}, инициализация агрегата используется для инициализации a до 0. Однако, когда вы выполняете Y y = {0}, так как struct Y не является агрегированным типом, компилятор будет искать соответствующий конструктор. Поскольку ни один из неявно созданных конструкторов (по умолчанию, копирование и перемещение) не может делать ничего с одним целым числом, компилятор отклоняет ваш код.


Что касается этого поиска конструкторов, сообщения об ошибках из clang++ немного более ясны в отношении того, что на самом деле пытается сделать компилятор (онлайн-пример):

Y Y = {0};
  ^   ~~~

main.cpp:5:8: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'int' to 'const Y &' for 1st argument

struct Y : public X {};
       ^

main.cpp:5:8: note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'int' to 'Y &&' for 1st argument

struct Y : public X {};
       ^

main.cpp:5:8: note: candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 1 was provided

Обратите внимание, что существует предложение, чтобы расширить агрегированную инициализацию для поддержки вашего варианта использования, и он превратился в С++ 17. Если я прочитаю его правильно, это сделает ваш пример действительным с семантикой, которую вы ожидаете. Итак... вам остается только ждать компилятора, совместимого с С++ 17.