Срок действия и / или продление времени жизни mem-инициализатора при агрегированной инициализации

CWG 1815 спросила (с небольшими изменениями):

struct A {};
struct B { A&& a = A{}; };
B b1;         // #1
B b2{A{}};    // #2
B b3{};       // #3

[...] #2 - это агрегированная инициализация, которая связывает B::a с временным параметром в инициализаторе для b2 и, таким образом, продлевает его время жизни до времени b2. #3 - это агрегированная инициализация, но неясно, должно ли время жизни временного элемента в инициализаторе нестатических элементов данных для B::a продлеваться, как #2, или нет, как #1.

Согласно примечаниям по этой проблеме, на Issaquah (2014-02) CWG намеревалась заставить #3 вести себя как #2; то есть правильно сформированный и продлевающий время жизни временного объекта, к которому привязан b3.a. Но на следующем заседании ISO (Рапперсвиль, 2014-06) резолюция CWG 1696 была принята, якобы разрешив CWG 1815, но приняв что , похоже, делает #3 неверно сформированным:

11 - Временное выражение, привязанное к ссылочному элементу из инициализатора элемента по умолчанию, имеет неправильный формат.

Однако пример непосредственно под этим пунктом не рассматривает агрегатную инициализацию (как в CWG 1815), а только инициализацию конструктором; в частности, конструктор по умолчанию, определенный как заданный по умолчанию:

struct A {
  A() = default;        // OK
  A(int v) : v(v) { }   // OK
  const int& v = 42;    // OK
};
A a1;                   // error: ill-formed binding of temporary to reference
A a2(1);                // OK, unfortunately

Таким образом, хотя формулировка кажется ясной, она также может показаться противоречащей намерению Комитета, что может быть основанием для того, чтобы считать формулировку дефектной.

Что касается практики реализации, мы можем увидеть, что существуют значительные расхождения:

gcc clang MSVC ICC
#1 ❌ destroy ✅ reject ☠️ leak ❌ destroy
#2 ✅ extend ✅ extend ✅ extend ✅ extend
#3 ❌ extend ❌ extend ❌ extend ❌ destroy

(Здесь уничтожить означает, что временный объект уничтожен в конце объявления, т.е. не продлен срок службы. ✅ указывает на соответствие, ❌ несоответствие, ☠️ явный дефект.) Однако, кроме ICC, компиляторы соглашаются продлить время жизни в #3 , вопреки нынешней формулировке. Как ни странно, несмотря на продление срока службы, Clang предупреждает, что сделать это не может, указывая на то, что разработчики считают продление срока службы необходимым стандартом в этом случае:

предупреждение: извините, продление срока службы временного объекта, созданного совокупной инициализацией с использованием инициализатора члена по умолчанию, не поддерживается; время жизни временного закончится в конце полного выражения [-Wdangling]

Вопрос

Учитывая выраженное намерение CWG и вариативность реализации, разумно ли считать текущую формулировку дефектной и полагаться на продление срока службы, имеющееся в #3? Знает ли Комитет об этом несоответствии и есть ли перспектива его устранения в ближайшей или среднесрочной перспективе (например, как DR на C ++ 20)?


person ecatmur    schedule 01.01.2021    source источник
comment
Мне кажется, что с 1815 года комитет вообще осуждает попытки инициализировать ссылочные элементы с помощью инициализаторов элементов по умолчанию. Так что было бы лучше, если бы все участники просто этого не делали. Следовательно, мы говорим ОК, к сожалению, для одного из примеров конструкторов, которые работают.   -  person Nicol Bolas    schedule 01.01.2021
comment
@NicolBolas, который не инициализирует ссылочный член через инициализатор члена по умолчанию, а через mem-initializer, для lvalue, которое оказывается параметром конструктора. См. stackoverflow.com/questions/52147940/   -  person ecatmur    schedule 01.01.2021
comment
Есть ли в агрегированной инициализации mem-initializer?   -  person Language Lawyer    schedule 02.01.2021
comment
@LanguageLawyer нет, mem-initializer могут появляться только в определении конструктора.   -  person ecatmur    schedule 02.01.2021