Когда я запускаю этот код:
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’
Почему инициализация фигурной скобки работает для базового класса, но не для производного класса?
Ваша проблема связана с агрегатная инициализация: struct X
это совокупность в то время как struct Y
не является. Вот стандартная цитата о агрегатах (8.5.1):
Агрегат — это массив или класс (раздел 9) без предоставленных пользователем конструкторов (12.1), без инициализаторов скобок или равных для нестатических элементов данных (9.2), без закрытых или защищенных нестатических элементов данных ( Пункт 11), нет базовых классов (пункт 10) и нет виртуальных функций (10.3).
В этом пункте указывается, что если class
имеет базовый класс, то это не агрегат. Вот, struct Y
имеет struct X
как базовый класс и, следовательно, не может быть агрегатным типом.
Относительно конкретной проблемы, которую вы имеете, возьмите из стандарта следующее предложение:
Когда агрегат инициализируется списком инициализаторов, как указано в 8.5.4, элементы списка инициализаторов берутся в качестве инициализаторов для элементов агрегата в порядке возрастания индекса или элемента. Каждый член инициализируется копией из соответствующего предложения инициализатора. Если предложение-инициализатор является выражением, и для преобразования выражения требуется сужающее преобразование (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
Обратите внимание, что есть предложение расширить совокупную инициализацию для поддержки вашего варианта использования, а также это сделало это в C ++ 17. Если я читаю это правильно, это делает ваш пример верным с ожидаемой вами семантикой. Итак … вам нужно только ждать компилятора, совместимого с C ++ 17.
Других решений пока нет …