Расширяют ли ссылки на const в структурированных привязках время жизни разложенного объекта?
Делает запись 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. Более уродливый, реализующий все навороты для моего собственного типа, похоже, продлевает время жизни внешнего объекта и других его членов данных.
Хотя почти наверняка намерения автора (-ов), я хотел бы знать наверняка, что язык гарантирует, что это безопасно.
1 ответ
Да. Хитрость заключается в том, чтобы понять, что, несмотря на внешний вид, часть объявления структурированной привязки перед [
не относится к именам в списке идентификаторов. Вместо этого они применяются к переменной, неявно введенной объявлением. [dcl.struct.bind] / 1:
Во-первых, переменная с уникальным именем
e
вводится. Если присваивание-выражение в инициализаторе имеет тип массиваA
и нет реф-классификатора присутствует,e
имеет типcv A
и каждый элемент инициализируется копией или инициализируется напрямую из соответствующего элемента выражения присваивания, как указано в форме инициализатора. Иначе,e
определяется как-будтоатрибут-спецификатор-seqопт decl-спецификатор-seq реф-квалификаторопт
e
инициализатор;где объявление никогда не интерпретируется как объявление функции, а части объявления, отличные от идентификатора объявления, берутся из соответствующего объявления структурированной привязки.
Затем имена определяются как псевдонимы для элементов 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
возвращаемое значение.