while utilizar usar usa switch lenguaje instruccion funcion con como ciclo c++ gcc lambda switch-statement

c++ - utilizar - Error de gcc cuando se usa una instrucción switch con un caso predeterminado y una función lambda



switch instruccion (4)

Debe encerrar el cuerpo de su case ''g'' entre llaves. Esto no se debe a la lambda per se, sino a la creación de cualquier nueva variable en una declaración de caso.

Sin el valor predeterminado, supongo que no se queja porque solo hay un lugar donde puede fluir la ejecución. Pero con valores predeterminados y sin llaves, tiene un problema porque el alcance de f extiende al código default , pero no se inicializará allí.

No entiendo por qué este código

#include <iostream> class A { public: void foo(){ char g = ''m''; switch(g){ case ''g'': auto f = [](){std::printf("hello world/n");}; f(); break; // default: // std::printf("go to hell/n"); // break; } }; }; int main(int iargc, char *iargv[]){ A a; a.foo(); }

compila (y funciona) bien, mientras que al descomentar la instrucción predeterminada

#include <iostream> class A { public: void foo(){ char g = ''m''; switch(g){ case ''g'': auto f = [](){std::printf("hello world/n");}; f(); break; default: std::printf("go to hell/n"); break; } }; }; int main(int iargc, char *iargv[]){ A a; a.foo(); }

me da el siguiente mensaje de error

test.cpp:15:13: error: jump to case label [-fpermissive] default: ^ test.cpp:12:22: error: crosses initialization of ‘A::foo()::__lambda0 f’ auto f = [](){std::printf("hello world/n");};

Puedo usar una declaración predeterminada, si hago un comentario sobre la función lambda.

Estoy usando gcc 4.8.5.


El mensaje de error te dice exactamente cuál es el problema. Saltar a la etiqueta default va desde un punto donde f no está en el alcance hasta un punto donde está dentro del alcance, omitiendo su inicialización.

La regla relevante del estándar es:

6.7 Declaración de declaración [stmt.dcl]

Es posible transferir a un bloque, pero no de una manera que puentee las declaraciones con la inicialización. Un programa que salta desde un punto donde una variable con duración de almacenamiento automática no está en alcance hasta un punto en el que está dentro del alcance está mal formado a menos que la variable tenga tipo escalar, tipo de clase con un constructor trivial predeterminado y un destructor trivial, versión cv-calificada de uno de estos tipos, o una matriz de uno de los tipos anteriores y se declara sin un inicializador (8.6).

Cuando solo tiene un case para el cambio, no hay forma de saltar sobre la inicialización, porque el único lugar donde puede ingresar la instrucción de cambio es en la primera etiqueta de caso, que no pierde la inicialización. Si no omites la inicialización de la variable, entonces no hay problema.

No obtiene el error para tipos como double o int porque son de tipo escalar (por lo que si salta sobre su inicialización están dentro del alcance, pero no están inicializados). El tipo de cierre creado por el lambda no es un tipo escalar, y no se declara sin un inicializador.


envuelva su código entre llaves o se considera como el mismo bloque.

Saltar al valor predeterminado omite la declaración de variables.

case ''g'': { auto f = [](){std::printf("hello world/n");}; f(); break; }


switch(g){ case ''g'': auto f = [](){std::printf("hello world/n");}; f(); break; default: std::printf("go to hell/n"); break; }

Un switch transfiere el control a una de sus etiquetas. Todas estas etiquetas están en el bloque único introducido por la instrucción switch.

El estándar (N4296 §6.7 / 3) dice (el énfasis es mío):

Es posible transferir [control] a un bloque, pero no de forma que evite las declaraciones con inicialización . Un programa que salta desde un punto donde una variable con duración de almacenamiento automática no está en alcance hasta un punto en el que está dentro del alcance está mal formado a menos que la variable tenga tipo escalar, tipo de clase con un constructor trivial predeterminado y un destructor trivial, versión cv-calificada de uno de estos tipos, o una matriz de uno de los tipos anteriores y se declara sin un inicializador.

Por lo tanto, dado que es posible transferir el control directamente a la etiqueta default , más allá de la declaración y la inicialización de la lambda f (que no es trivialmente construible), su programa está mal formado y el compilador lo rechaza legítimamente.