ultima gnuc compiler compilador c++ gcc c++17 structured-bindings gcc7

c++ - gnuc - ¿Por qué la inclusión de<utilidad> rompe los enlaces estructurados en GCC?



gnu g++ compiler (2)

Considerar:

struct Point { int x, y; }; int main() { const auto [x, y] = Point{}; }

Este código compila bien con gcc 7.1 en modo C ++ 17, sin embargo, este:

#include <utility> struct Point { int x, y; }; int main() { const auto [x, y] = Point{}; }

da un error:

bug.cpp: In function ''int main()'': bug.cpp:7:16: error: ''std::tuple_size<const Point>::value'' is not an integral constant expression const auto [x, y] = Point{}; ^~~~~~

¿Que está pasando aqui? ¿Un error de compilación, o es así como se supone que funcionan los enlaces estructurados?


Este es el compilador de errores 78939 . Aunque es un poco más complicado que eso, hubo algunos problemas entre el lenguaje central y la biblioteca que fueron mutuamente contradictorios ( GB 20 , LWG 2770 y LWG 2446 ), que conducen al tipo de comportamiento que muestran gcc / libstdc ++ aquí . Ciertamente, se pretende que el código funcione con o sin #include <utility> , es solo una cuestión de que la redacción estándar haya llegado correctamente.

Sí, las clases con todos los miembros de la unión pública no anónima deberían poder utilizarse en declaraciones de enlaces estructurados por [dcl.struct.bind]/4 :

De lo contrario, todos los miembros de datos no estáticos de E serán miembros públicos directos de E o de la misma clase de base pública no ambigua de E , E no tendrá un miembro anónimo de la unión, y el número de elementos en la lista de identificadores ser igual al número de miembros de datos no estáticos de E Designando a los miembros de datos no estáticos de E como m0, m1, m2, ... (en orden de declaración), cada vi es el nombre de un valor de l que se refiere al miembro mi de e y cuyo tipo es cv Ti, donde Ti es el tipo declarado de ese miembro; El tipo referenciado es cv Ti. El valor l es un campo de bits si ese miembro es un campo de bits. [Ejemplo:

struct S { int x1 : 2; volatile double y1; }; S f(); const auto [ x, y ] = f();

Esto no tiene nada que ver con la inclusión de <utility> , nada en este código depende de ninguna funcionalidad de la biblioteca: los miembros se capturan directamente y no a través del mecanismo get / tuple_size .


La idea central detrás de los enlaces estructurados es que std::tuple_size<T> define cuántos componentes obtiene al desempaquetar T , y T::get<N> debe acceder al elemento N''th. No es sorprendente, este std::tuple_size<T> es una especialización de la plantilla base en <utility> .

Ahora, en este caso, Point no tiene tal soporte para enlaces estructurados, pero es un caso especial (todos los miembros públicos no estáticos) para el cual C ++ 17 indica que no se necesita un soporte especial para desempaquetar. Esta es una excepción a la regla anterior.

El compilador se está disparando sobre sí mismo aquí, e intenta usar la regla genérica cuando ve el std::tuple_size no especializado de <utility> .