Ответ 1
Чтение снова и снова стандарта, я думаю, что это ошибка.
Что говорит стандарт?
8.5.1/2. Когда агрегат инициализируется списком инициализаторов, как указано в 8.5.4, элементы списка инициализаторов берутся как инициализаторы для членов совокупности, увеличивая индекс или порядок членов. Каждый член инициализируется с помощью соответствующее предложение инициализатора.
Объясняется, что:
8.5/14: (...) называется копией-инициализацией. [Примечание. Копирование-инициализация может вызвать ход (12.8). -end note]
Но я не нашел доказательств в 12.8, что в вашем конкретном случае потребуется переход.
8.5.4/3 В противном случае, если T - тип класса, рассматриваются конструкторы. Если T имеет конструктор-инициализатор-список, аргумент список состоит из списка инициализаций как один аргумент; в противном случае, список аргументов состоит из элементов списка инициализаторов. Соответствующие конструкторы перечислены и выбираются лучшие через разрешение перегрузки (13.3).
Итак, в принципе, код должен работать!
Это ошибка? Попытка экспериментального способа
Я прокомментировал удаление конструктора перемещения, чтобы воспользоваться неявным конструктором перемещения. Как ни странно, я получил следующее сообщение об ошибке:
Compilation error time: 0 memory: 3232 signal:0
prog.cpp: In constructor 'Aggr::Aggr()':
prog.cpp:19:28: error: use of deleted function 'A::A(const A&)'
Aggr() : arr{{"a"}, {"b"}} {}
^
prog.cpp:10:3: note: declared here
A(const A&) = delete
Итак, теперь он жалуется на недостающий конструктор копий!
Еще более странно, я тогда предоставил свой собственный конструктор перемещения вместо неявного: здесь он скомпилировал код успешно!
Наконец, я предоставил как копию, так и переход и добавил некоторые трассировки:
class A {
private:
std::string s;
public:
A() = delete;
A(const A&) { std::cout<<"copy\n";} //= delete;
A(A&&) { std::cout<<"move\n";} //= delete;
A(const std::string &a) : s(a) { std::cout<<"string ctor\n";}
};
И когда я создаю объект Aggr
, он просто отображает:
string ctor
string ctor
показывающий, что элемент массива инициализирован, формирует конструктор строк, используя копию elision, как мы и ожидали.
Все эти тесты были выполнены с помощью gcc-9.4.2 на ideone с параметром С++ 14.
Заключение
Тот факт, что тот же код не скомпилирован с неявным движением ctor и преуспевает с пользовательским движением ctor, выглядит очень серьезно, как ошибка.
Тот факт, что конструктор перемещения не используется, когда он доступен, усиливает это впечатление.
Следовательно, я сообщил эту ошибку.