Ответ 1
TL; DR: Clang и GCC ошибочны в отказе от вашего кода. Разрешение CWG 1630 сделало инициализацию по умолчанию корректной, независимо от выбранного конструктора по умолчанию explicit
или нет.
В вариации вашего кода, в котором i
есть private
, A
не является совокупностью, так как у них не могут быть частные члены. Тем не менее, i
public
, A
является агрегатом 1 и никакой конструктор не вызывается, поскольку выполняется инициализация агрегата (см. Синюю рамку), поэтому ваш конструктор explicit
не имеет значения.
Однако, как только вы вводите частный член, вам необходимо инициализировать инициализацию значения в соответствии с красным полем. Следовательно, применяется [dcl.init]/(8.2):
[dcl.init]/(7.1) определяет инициализацию по умолчанию для этого случая:
И в §13.3.1.3 дается
Для [...] инициализации по умолчанию кандидат функции - все конструкторы класса объекта, являющегося инициализированы.
Ни в коем случае не рассматривается исходный контекст - копирование или прямая инициализация. (П. 13.3.1.7 также не применяется). На самом деле это предназначено; см. CWG # 1518:
Эта проблема разрешена решением issue 1630: инициализация по умолчанию теперь использует 13.3.1.3 [over.match.ctor ], который теперь позволяет явным конструкторам инициализации по умолчанию.
Clang и GCC (и VС++) еще не реализовали соответствующий DR и, таким образом, неверны при отклонении кода в режиме С++ 14.
1) У вашего класса есть конструктор, объявленный пользователем, но он не предоставляется пользователям, то есть не мешает вашему классу быть агрегированным. Напомним определение в [dcl.init.aggr]/1:
Агрегат - это массив или класс (раздел 9) без каких-либо пользовательских конструкторы (12.1), частные или защищенные нестатические элементы данных (Раздел 11), нет базовых классов (раздел 10) и нет виртуальных функций (10.3).