Я думаю, что это ошибка в g cc.
Как указано в C ++ 17 [dcl.init.aggr] / 3 (этот текст был практически таким же в C ++ 14) :
Когда агрегат инициализируется списком инициализаторов, как указано в 11.6.4, элементы списка инициализаторов берутся в качестве инициализаторов для элементов агрегата по порядку. Каждый элемент инициализируется копией из соответствующего предложения инициализатора . [...] Если предложение инициализатора само является списком инициализатора, элемент инициализируется списком,
Я проанализирую три различных случая здесь:
- Дело 1:
mem { id, id }
- Дело 2:
mem { MemberClass{id}, MemberClass{id} }
- Дело 3:
mem { {id}, {id} }
В деле 1, mem[0]
инициализируется копией выражением id
. Это тот же тип инициализации, что и MemberClass x = id;
. Он описан в dcl.init / 17.6.2 (инициализация копирования из выражения другого типа).
Поведение заключается в том, что инициализатор преобразуется в значение типа (то есть MemberClass{id}
), которое затем направляет инициализирует цель. В C ++ 14 это было неправильно: несмотря на то, что это контекст копирования, действительный конструктор копирования все еще должен существовать. В C ++ 17 это правильно: инициализация объекта из prvalue того же типа аналогична инициализации объекта с использованием конструктора, указанного в prvalue (так называемое «гарантированное разрешение копирования»).
Случай 2 аналогичен случаю 1: в нем используется 17.6.1 (инициализация из выражения того же типа), и применяется тот же анализ для случая 1.
Однако, случай 3 отличается. В соответствии с последней жирной цитатой из dcl.init.aggr / 3, mem[0]
инициализируется списком на {id}
, то есть код должен вести себя так же, как MemberClass z {id};
. Нет временной операции или операции копирования даже в C ++ 14.
Поэтому правильное поведение:
- C ++ 14 - Случай 3 верный, Случай 1 и 2 плохой -formed.
- C ++ 17 - Все случаи правильны.
Сообщения об ошибках, выдаваемые g cc, предполагают, что он в режиме C ++ 14 обрабатывает Случай 3, ваш код, такой же, как и в двух других случаях. А в режиме C ++ 17 он никогда не получал памятку о гарантированном разрешении копирования.