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

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

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’

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

34

Решение

Ваша проблема связана с агрегатная инициализация: 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.

43

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

Других решений пока нет …

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