Это новая функция, добавленная в C ++ 17. То, что происходит, C
теперь считается совокупностью. Поскольку это агрегат, ему не нужен конструктор. Если мы посмотрим на [dcl.init.aggr] / 1 , то получим, что агрегат равен
Агрегат - это массив или класс с
нет пользовательских, явных или унаследованных конструкторов ([class.ctor]),
нет личных или защищенных нестатических элементов данных (пункт [class.access]),
без виртуальных функций и
нет виртуальных, частных или защищенных базовых классов ([class.mi]).
[Примечание. Совокупная инициализация не позволяет получить доступ к защищенным и закрытым членам или конструкторам базового класса. - конец примечания]
И мы проверяем все эти пункты. У вас нет конструкторов, объявленных в C
или D
, поэтому есть маркер 1. У вас нет элементов данных, поэтому второй маркер не имеет значения, а ваш базовый класс общедоступен, поэтому третий маркер удовлетворены.
Изменения, произошедшие между C ++ 11/14 и C ++ 17, которые позволяют это, заключаются в том, что агрегаты теперь могут иметь базовые классы. Вы можете увидеть старую формулировку здесь , где прямо указано, что базовые классы не допускаются.
Мы можем подтвердить это, проверив черту std::is_aggregate_v
как
int main()
{
std::cout << std::is_aggregate_v<C>;
}
который напечатает 1.
Обратите внимание, что, поскольку C
является другом B
, вы можете использовать
C c{};
C c1;
C c2 = C();
Как допустимые способы инициализации C
. Поскольку D
не является другом B
, единственное, что работает, это D d{};
, поскольку это агрегатная инициализация. Все остальные формы пытаются инициализировать по умолчанию, и это невозможно сделать, так как D
имеет удаленный конструктор по умолчанию.