Я перевожу проект Visual Studio C++ с VS2017 на VS2019.
Сейчас я получаю сообщение об ошибке, которого раньше не было, которое можно воспроизвести с помощью нескольких строк кода:
struct Foo
{
Foo() = default;
int bar;
};
auto test = Foo { 0 };
Ошибка
(6): ошибка C2440: "инициализация": невозможно преобразовать из 'список инициализатора' в 'Foo'
(6): примечание: ни один конструктор не может взять тип источника, или Разрешение перегрузки конструктора было неоднозначным
Проект скомпилирован с флагом /std:c++latest
. Я воспроизвел это на Годболте. Если я переключаю его на /std:c++17
, он прекрасно компилируется, как и раньше.
Я попытался скомпилировать тот же код с clang с -std=c++2a
и получил похожую ошибку. Кроме того, по умолчанию или удаление других конструкторов генерирует эту ошибку.
По-видимому, некоторые новые функции C++ 20 были добавлены в VS2019, и я предполагаю, что происхождение этой проблемы описано в https://en.cppreference.com/w/cpp/language/aggregate_initialization. Там говорится, что агрегат может быть структурой, которая (среди прочих критериев) имеет
- не предоставленные пользователем, унаследованные или явные конструкторы (конструкторы по умолчанию или удаленные по умолчанию не допускаются) (начиная с C++ 17) (до C++ 20)
- нет объявленных или наследуемых конструкторов (начиная с C++ 20)
Обратите внимание, что часть в скобках "явно заданные по умолчанию или удаленные конструкторы разрешены" была удалена, а "предоставленная пользователем" заменена на "объявленная пользователем".
Итак, мой первый вопрос: правильно ли я полагаю, что это изменение в стандарте является причиной, по которой мой код компилировался раньше, но больше этого не делает?
Конечно, это легко исправить: просто удалите явно дефолтные конструкторы.
Тем не менее, я явно по умолчанию и удалил очень много конструкторов во всех моих проектах, потому что я нашел хорошей привычкой делать код гораздо более выразительным таким образом, потому что это просто приводит к меньшему количеству сюрпризов, чем с неявно дефолтными или удаленными конструкторами. Однако с этим изменением это уже не кажется такой хорошей привычкой...
Итак, мой актуальный вопрос: Каковы причины этого изменения с C++ 17 на C++ 20? Был ли этот разрыв обратной совместимости сделан специально? Был ли какой-то компромисс, такой как "Хорошо, мы нарушаем обратную совместимость здесь, но это для большей пользы"? Что это больше хорошего?