Почему, казалось бы, все компиляторы отвергают следующую программу? (https://godbolt.org/z/EK8zW34nY)
struct A
{
explicit A() {}
};
int main()
{
A a = {};
}
a должен быть инициализирован по значению в соответствии с [dcl.init.list]/3.5, насколько я могу судить, и это, в свою очередь, должно выбрать конструктор, как при инициализации по умолчанию a Инициализация по умолчанию не исключает explicit конструкторы.
Это продолжение обсуждения с другим пользователем в другом вопросе:
Если бы можно было применить [over.match.list], что, я думаю, не следует применять здесь, тогда это потерпит неудачу из-за «При инициализации списка копирования, если выбран явный конструктор, инициализация имеет неверный формат». .».
При изменении программы на
struct A
{
explicit A() {}
template<typename = void>
A() {}
};
int main()
{
A a = {};
}
затем GCC и Clang по-прежнему отклоняют его с сообщениями об ошибках, намекая, что они так считают, в то время как EDG и MSVC принимают, выбирая шаблонный конструктор, как если бы существовала «инициализация копирования по умолчанию», которая полностью исключает явные конструкторы. (https://godbolt.org/z/xbzjhYYhM)





Когда ты это делаешь
A a = {};
Вы используете инициализацию списка копирования, которая вводит [over.match.ctor], в которой говорится:
Когда объекты типа класса инициализируются напрямую, копируются из выражения того же типа или типа производного класса ([dcl.init]) или инициализируются по умолчанию, разрешение перегрузки выбирает конструктор. Для прямой инициализации или инициализации по умолчанию (включая инициализацию по умолчанию в контексте инициализации списка копирования) функциями-кандидатами являются все конструкторы класса инициализируемого объекта. В противном случае функциями-кандидатами являются все преобразующие конструкторы ([class.conv.ctor]) этого класса. Список аргументов — это список выражений или выражение присваивания инициализатора. Для инициализации по умолчанию в контексте инициализации списка копирования, если выбран явный конструктор, инициализация будет неправильной.
А поскольку объект не инициализируется выражением того же или производного типа, применяется вторая половина, а последняя часть последнего предложения делает код плохо сформированным.
Это имеет смысл, поскольку {} не является A, это неявный создатель объекта, и вы не можете создать неявный объект из типа, который имеет явный конструктор по умолчанию.
Ах, я заметил, что пропустил текущую формулировку в конце, когда вы тоже редактировали свой вопрос.
Оказалось, что это проблема понимания прочитанного. Конец [over.match.ctor] после CWG 2856 говорит:
Для инициализации по умолчанию в контексте инициализации списка копирования, если выбран явный конструктор, инициализация будет неправильной.
Таким образом, GCC и Clang ведут себя правильно, хотя вместо [over.match.list] применяется [over.match.ctor].
MSVC и EDG, вероятно, еще не реализовали отчет о дефектах. До сообщения об этом дефекте формулировка [over.match.ctor] исключала explicit конструкторы для прямой инициализации в контексте инициализации списка копирования.
@user17732522 user17732522 Обновлен, я считаю, правильный раздел.