Я поощряю с этой проблемой:
Если у меня есть
class A
{
public:
};
int main()
{
A a{};
A b{a};
}
GCC дает:
move.cc: В функции int main ():
move.cc:15:7: ошибка: слишком много инициализаторов для «A»
A b {a};
Но когда я использую A b (a) вместо A b {a}, все компилируется правильно. И если я объявляю конструктор по умолчанию, он тоже компилируется. Почему так работает?
Класс является агрегатом, поэтому инициализация списка будет выполнять агрегатную инициализацию и не будет учитывать неявно объявленные конструкторы.
Так как нет элементов данных, только пустой список может быть допустимым агрегатным инициализатором.
Но когда я использую
A b(a)
вместоA b{a}
все компилируется правильно.
При прямой инициализации будет использоваться неявный конструктор, а не попытка агрегированной инициализации.
И если я объявляю конструктор по умолчанию, он тоже компилируется.
Объявляя конструктор, класс больше не является агрегатом, и его можно инициализировать только с помощью конструктора.
Когда не определяешь свой конструкторы class A
будет считаться совокупный (То есть. набившие оскомину-данные) тип хранения.
Имея дело с совокупностью, Список инициализация не будет рассматривать неявно объявленные конструкторы, вместо этого он попытается инициализировать члены вашего объекта напрямую.
В случае A b { a }
где A
это агрегат, который компилятор попытается инициализировать первым A
со значением a
; это, конечно, потерпит неудачу, так как A
не содержит участников.
[8.5.1 Aggregates]
1) Агрегат — это массив или класс (раздел 9) без предоставления пользователем
конструкторы (12.1), нет скобки или равных инициализаторов для нестатических
элементы данных (9.2), нет частных или защищенных нестатических элементов данных
(Раздел 11), без базовых классов (раздел 10) и без виртуальных функций
(10.3).
2) Когда агрегат инициализируется списком инициализаторов, как
указанные в 8.5.4, элементы инициализатора принимаются как
инициализаторы для членов агрегата, в возрастающем индексе
или заказ участника. Каждый член инициализируется копией из
соответствующее предложение-инициализатор. Если предложение инициализатора является
Выражение и сужающее преобразование (8.5.4) требуется для преобразования
выражение, программа плохо сформирована.
GCC следовал стандарту, но это был известный дефект, см. основной вопрос 1467. Отчет о дефектах был исправлен в ноябре 2014 года, и новое поведение поддерживается в следующем основном выпуске GCC (версия 5.1, выпущенная в апреле 2015 года).