Инициализация списка в массиве без временных значений - не работает в GCC
Рассмотрим следующий надуманный пример
struct A {
A(int) {}
A(const A&) = delete;
~A() {}
};
struct B {
A a[2] = {{1}, {2}};
};
int main() {
B b;
}
Он прекрасно компилируется в clang (любая версия), но не в GCC (любая версия, любой стандарт> = С++ 11)
<source>: In constructor 'constexpr B::B()':
<source>:7:8: error: use of deleted function 'A::A(const A&)'
struct B {
^
<source>:3:5: note: declared here
A(const A&) = delete;
^
<source>: In function 'int main()':
<source>:12:7: note: synthesized method 'constexpr B::B()' first required here
B b;
^
LIVE DEMO
Когда деструктор закомментирован, он прекрасно компилируется и в GCC.
Вопрос - кто прав, лязг или GCC и почему?
Первоначально я думал, что GCC не так, но потом я увидел [dcl.init.list]/5, в котором говорится, что создаются временные. Хотя я не уверен, применимо ли это здесь или есть другое правило, которое отменяет это.
Ответы
Ответ 1
Поскольку массив является агрегатом, а агрегатная инициализация сводится к копированию-инициализации агрегатных элементов из элементов списка инициализаторов, вопрос в основном заключается в следующем: выполняет ли копирование-список-инициализацию (элементов массива a[0]
и a[1]
из {1}
и {2}
, соответственно) требуется конструктор копирования, но на этот вопрос уже был дан ответ - нет.
Кстати, GCC принимает A a = {1};
то есть у него нет проблем с "прямой" инициализацией копирования списка, но он не обрабатывает это правильно, когда члены агрегатов инициализируются.
Ответ 2
Это, среди миллионов других причин, является причиной того, что так много людей оставляют этот отвратительный язык позади и переходят к гораздо лучшим вещам.