Ответ 1
Итак, в тех случаях, когда E является классом, все они выглядят как нарушения odr, если мы смотрим на странице cppreferences на odr-use it говорит:
Неофициально, объект используется odr, если его адрес занят, или ссылка привязана к нему, а функция используется odr, если выполняется вызов функции или ее адрес. Если объект или функция используется odr, его определение должно существовать где-то в программе; нарушением которой является ошибка времени соединения.
и в этом случае мы берем ссылку, когда мы вызываем конструктор копирования в этой строке:
show(x.nested);
Также стоит отметить, что odr-нарушения не требуют диагностики.
Похоже, что вы видите в некоторых случаях эффекты конструктора elision с gcc, если мы используем - fno-elide-constructors, мы получить ошибку для всех случаев, когда E - класс. В случаях перечисления применяется преобразование lvalue-rvalue и, следовательно, нет использования odr.
Обновить
dyp указал мне на отчет о дефекте 1741, в котором задается вопрос о том, является ли привязка к ссылочному параметру копии ctor нецелевым использованием или нет:
Использует ли этот odr-использование T:: s, требуя, чтобы он имел определение, из-за привязки его к эталонному параметру конструктора S-копии?
и результатом было следующее изменение в пункте 3 [basic.def.odr]:
Переменная x, имя которой отображается как потенциально оцениваемое выражение ex, используется odr, если
x не удовлетворяет требованиям к появлению в константном выражении (5.20 [expr.const]), применяя преобразование lvalue-to-rvalue (4.1 [conv.lval]) в x дает константное выражение (5.20 [expr.const]), которое не вызывает никаких нетривиальных функций и, если x - объект, ex - элемент множества потенциальных результатов выражения e, где либо преобразование lvalue-to-rval (4.1 [conv.lval]) применяется к e, либо e является выражением отбрасываемого значения (пункт 5 [expr ]). это используется odr...
Итак, возникает вопрос, какие случаи охватываются этим изменением. Казалось бы, эти примеры в порядке:
//static constexpr struct E {} nested {}; // works in gcc and clang
//static constexpr struct E {T x;} nested {}; // doesn't work in gcc
static constexpr struct E { constexpr E() {} constexpr E(const E&) = default; T x=T(); } nested {}; // doesn't work in gcc
Так как копия ctor тривиальна, а эта не является тривиальной:
//static constexpr struct E { constexpr E() {} constexpr E(const E&) {} T x=T();} nested {}; // works in gcc and clang
Мы можем подтвердить это, используя std:: is_trivially_copyable, посмотреть он живет.
Дела перечисления по-прежнему в порядке по тем же причинам, которые я изначально заявил.
Дефект также сообщает о разнице в реализации.