Продлевают ли константные ссылки в структурированных привязках время жизни разложенного объекта?

Гарантирует ли запись const auto& [a, b] = f(); продление срока службы объекта, возвращаемого из f(), или, по крайней мере, объекты, к которым привязаны a и b? Читая предложение, я не вижу ничего очевидного в язык, чтобы убедиться, что это так, если только он не покрыт чем-то другим. Однако следующее не продлевает срок службы временного объекта, поэтому я не понимаю, как это будет покрыто:

const auto& a = std::get<0>(f());

В верхней части бумаги кажется, что она покрыта

квалификаторы cv и ref объявления декомпозиции применяются к ссылке, введенной для инициализатора, а не для отдельных псевдонимов членов

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

если e является выражением id без скобок, именующим lvalue или ссылку, введенную из списка идентификаторов объявления декомпозиции, decltype(e) является типом, на который указывает ссылка, как указано в спецификации объявления декомпозиции

Похоже, что gcc и clang продлевают время жизни возвращаемого объекта до конца области видимости на основе эксперимента с wandbox. более уродливый, реализующий все навороты для моего собственного типа, кажется, продлевает время жизни внешнего объекта и других его данных. члены.

Хотя почти наверняка намерения авторов, я хотел бы знать наверняка, что язык гарантирует, что это безопасно.


person Ryan Haining    schedule 16.12.2016    source источник


Ответы (1)


Да. Хитрость заключается в том, чтобы понять, что, несмотря на внешний вид, часть объявления структурированной привязки перед [ не применяется к именам в списке-идентификаторов. Вместо этого они применяются к переменной, неявно введенной объявлением. [dcl.struct.bind]/1:

Во-первых, вводится переменная с уникальным именем e. Если выражение-присваивания в инициализаторе имеет тип массива A и отсутствует квалификатор ссылки, e имеет тип cv A и каждый элемент копируется -инициализируется или инициализируется напрямую из соответствующего элемента выражения-присваивания, как указано в форме инициализатора. В противном случае e определяется как если бы

attribute-specifier-seqopt decl-specifier-seq ref-qualifieropt e инициализатор ;

где объявление никогда не интерпретируется как объявление функции, а части объявления, отличные от declarator-id, берутся из соответствующего объявления структурированной привязки.

Затем имена определяются либо как псевдонимы для элементов e, либо как ссылки, привязанные к результату вызова get на e.

В вашем примере это как бы (при условии, что f возвращает двухэлементный std::tuple):

const auto& e = f(); // 1
using E = remove_reference_t<decltype((e))>;
std::tuple_element<0, E>::type& a = get<0>(e);
std::tuple_element<1, E>::type& b = get<1>(e);

(За исключением того, что decltype(a) и decltype(b) получают специальную обработку, чтобы скрыть их отсылку.)

Должно быть совершенно очевидно, что строка №1 продлевает время жизни возвращаемого значения f.

person T.C.    schedule 16.12.2016