c++ - after - ¿Las referencias const en enlaces estructurados prolongan la vida útil del objeto descompuesto?
const function c++ (1)
¿Se escribe const auto& [a, b] = f();
garantiza extender la vida útil del objeto devuelto desde f()
, o al menos los objetos a
y b
están vinculados a? Al leer la propuesta , no veo nada obvio en el lenguaje para asegurarme de que lo haga, a menos que esté cubierto por otra cosa. Sin embargo, lo siguiente no extiende la vida útil de lo temporal, por lo que no veo cómo se cubriría:
const auto& a = std::get<0>(f());
En la parte superior del documento parece sugerir que está cubierto
los calificadores cv y el calificador ref de la declaración de descomposición se aplican a la referencia introducida para el inicializador, no para los alias de miembros individuales
Pero en la redacción propuesta para el estándar actual, la mención más cercana que veo está abajo, aunque no estoy seguro de cómo leerlo para obtener la garantía que estoy buscando:
si e es una expresión-expresión sin paréntesis que nombra un valor o referencia introducida desde la lista de identificadores de una declaración de descomposición, decltype (e) es el tipo referenciado como se indica en la especificación de la declaración de descomposición
Parece que gcc y clang extienden la vida útil del objeto devuelto hasta el final del alcance basado en un experimento de wandbox . Uno más feo que implementa todas las campanas y silbidos para mi propio tipo parece extender la vida útil del objeto exterior y sus otros miembros de datos.
Aunque es casi seguro que la intención de los autores, me gustaría saber con seguridad que el lenguaje garantiza que esto es seguro.
Sí. El truco es darse cuenta de que, a pesar de la apariencia, la parte de una declaración de enlace estructurado antes de [
no se aplica a los nombres en la lista de identificadores . Se aplican en cambio a la variable introducida implícitamente por la declaración. [dcl.struct.bind]/1 :
Primero, se introduce una variable con un nombre único
e
. Si la expresión-asignación en el inicializador tiene un tipo de matrizA
y no está presente ningún ref-calificador ,e
tiene el tipocv A
y cada elemento se inicializa con copia o se inicializa directamente desde el elemento correspondiente de la expresión-asignación como se especifica en la forma del inicializador . De lo contrario,e
se define como-poratributo-especificador-seq opt decl-specifier-seq ref-qualifier opt
e
initializer ;donde la declaración nunca se interpreta como una declaración de función y las partes de la declaración distintas del declarator-id se toman de la declaración de enlace estructurado correspondiente.
Los nombres se definen para que sean alias para los elementos de e
o las referencias vinculadas al resultado de la llamada get
on e
.
En su ejemplo, es como si (asumiendo que f
devuelve un std::tuple
dos elementos):
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);
(Excepto que decltype(a)
y decltype(b)
reciben el tratamiento especial para ocultar su referencia).
Debería ser bastante obvio que la línea # 1 extiende la vida útil del valor de retorno de f
.