¿Cómo selecciono un rango de valores en una instrucción switch?

Cuando bash comstackr obtengo este error:

 1> ------ Build started: Project: snake, Configuración: Debug Win32 ------ 1> exercise.cpp 1> c: \ users \ robin \ documents \ visual studio 2010 \ projects \ snake \ snake \ exercise.cpp (13): error C2059: error de syntax: '> =' 1> c: \ users \ robin \ documents \ visual studio 2010 \ projects \ snake \ snake \ exercise.cpp (16): error C2059: syntax error: '> =' 1> c: \ usuarios \ robin \ documentos \ visual studio 2010 \ projects \ snake \ snake \ exercise.cpp (19): error C2059: error de syntax: '> =' 1> c: \ users \ robin \ documents \ visual studio 2010 \ projects \ snake \ snake \ exercise.cpp (22): error C2059: error de syntax: '> =' 1> c: \ users \ robin \ documents \ visual studio 2010 \ projects \ snake \ snake \ exercise.cpp (25): error C2059: error de syntax: '>' 1> c: \ users \ robin \ documents \ visual studio 2010 \ projects \ snake \ snake \ exercise.cpp (28): error C2059: error de syntax: '==' 1> c: \ users \ robin \ documents \ visual studio 2010 \ projects \ snake \ snake \ exercise.cpp (34): advertencia C4065: instrucción switch contiene 'default' pero no tags 'case' ========== Build: 0 exitoso, 1 fallido, 0 up-  hasta la fecha, 0 omitido ========== 

Código:

#include  using namespace std; int main(){ int score; //Vraag de score cout <> score; //Switch switch(score){ case >= 100: cout <= 50: cout <= 25: cout <= 10: cout < 0: cout << "e"; break; case == 0: cout << "f"; break; default: cout << "BAD VALUE"; break; } cout << endl; return 0; } 

¿Como puedo solucionar este problema? Es una aplicación de consola, Win32 y mi IDE es Windows Enterprise C ++ 2010.

Estoy aprendiendo desde el principio C ++ a través de la progtwigción de juegos .

En C ++ las tags de casos son expresiones constantes , no expresiones en general. Necesita una cadena de declaraciones if-then-else para hacer lo que está tratando de hacer.

Alternativamente, puede enumerar los valores en el interruptor. Esto funciona marginalmente más rápido (aunque no importa en casos como el suyo), pero es considerablemente menos legible:

 switch(score) { case 0: cout << "f"; break; case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: cout << "e"; break; case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23: case 24: case 25: cout << "c"; break; // ...and so on, you get the idea... } 

Algunos comstackdores admiten rangos de casos como case x ... y como una extensión del lenguaje C ++.

Ejemplo:

 #include  using namespace std; int main(){ int score; //Vraag de score cout << "Score:"; cin >> score; //Switch switch(score){ case 0: cout << "a"; break; case 0 ... 9: cout << "b"; break; case 11 ... 24: cout << "c"; break; case 25 ... 49: cout << "d"; break; case 50 ... 100: cout << "e"; break; default: cout << "BAD VALUE"; break; } cout << endl; return 0; } 

GCC 4.9 , Clang 3.5.1 y el comstackdor Intel C / C ++ 13.0.1 parecen soportarlo (probado en http://gcc.godbolt.org/ ). Por otro lado, Visual C ++ 19 no lo hace (probado en http://webcompiler.cloudapp.net/ ).

Puede solucionar este problema utilizando una serie de sentencias if / else if . Switch / case no se puede usar así en C ++.

Se puede hacer usando un std::map con switch :

 enum Interval { One, Two, Three, NotFound }; // [0,10[ is One, [10,30[ is Two, [30,55[ is Three std::map imap { { { 0, One }, { 10, Two }, { 30, Three }, { 55, NotFound } }; Interval ivalue = NotFound; auto f = imap.lower_bound( value ); if( f != imap.end() ) ivalue = f->second; switch( ivalue ) { case One : ... case Two : ... case Three : ... default: ... } 

Hay una extensión GCC que hace exactamente lo que quieres.

En C ++, una instrucción switch solo puede coincidir con valores enteros constantes:

 switch (i) { case 1: //... stuff break; case 2: //... stuff break; default: //... stuff } 

El estándar no permite esto:

6.4.2 La instrucción switch [stmt.switch]

[…] Cualquier statement dentro de la statement de cambio puede etiquetarse con una o más tags de caso de la siguiente manera:

case constant-expression :

donde la expresión constante será una expresión constante integral (5.19).

En otras palabras, solo puede usar mayúsculas y minúsculas que se expanden en una constante de tiempo de comstackción única, integral, “dura” (por ejemplo, case 5+6: enum {X = 3}; ... case X*X: .

La forma de evitar esto es usar if states. Por ejemplo, para reemplazar

 switch (x) case 0..100: 

tu en cambio

 if (x>=0 && x<=100) 

.

std::map::upper_bound + C ++ 11 lambdas

https://stackoverflow.com/a/35460297/895245 mencionado lower_bound , pero también podemos deshacernos de la enum allí con lambdas (o herencia si no la tienes).

 #include  #include  #include  int main() { std::string ret; const std::map> m{ {0, [&](){ ret = "too small"; }}, {2, [&](){ ret = "[0,2)"; }}, {5, [&](){ ret = "[2,5)"; }}, {7, [&](){ ret = "[5,7)"; }}, }; const auto end = m.end(); for (auto i = -1; i < 8; ++i) { auto it = m.upper_bound(i); if (it == end) { ret = "too large"; } else { it->second(); } std::cout << i << " " << ret << std::endl; } } 

Salida:

 -1 too small 0 [0,2) 1 [0,2) 2 [2,5) 3 [2,5) 4 [2,5) 5 [5,7) 6 [5,7) 7 too large 

Uso dentro de métodos con static

Para usar este patrón de manera eficiente dentro de las clases, inicialice el mapa lambda estáticamente, o bien pague n log(n) cada vez para comstackr desde cero.

Aquí podemos saltear con la {} inicialización de una variable de método static : variables estáticas en métodos de clase , pero también podríamos usar los métodos descritos en: constructores estáticos en C ++? Necesito inicializar objetos estáticos privados

Era necesario transformar la captura de contexto lambda [&] en un argumento, o que hubiera sido indefinido: const static auto lambda utilizado con captura por referencia

Ejemplo que produce el mismo resultado que el anterior:

 #include  #include  #include  #include  class RangeSwitch { public: void method(int x, std::string &ret) { static const std::map> m{ {0, [](std::string &ret){ ret = "too small"; }}, {2, [](std::string &ret){ ret = "[0,2)"; }}, {5, [](std::string &ret){ ret = "[2,5)"; }}, {7, [](std::string &ret){ ret = "[5,7)"; }}, }; static const auto end = m.end(); auto it = m.upper_bound(x); if (it == end) { ret = "too large"; } else { it->second(ret); } } }; int main() { RangeSwitch rangeSwitch; std::string ret; for (auto i = -1; i < 8; ++i) { rangeSwitch.method(i, ret); std::cout << i << " " << ret << std::endl; } } 

Simplemente no es así como funciona el interruptor. Solo toma valores individuales. Tendrás que usar bloques if-elseif

Tuve el mismo problema con un problema basado en puntaje y mientras que las declaraciones “if / elseif” eran buenas de usar, por intervalos encontré esa la mejor opción (al menos para mí porque me gusta cómo se ve y es más fácil para mí que principiante para ver mis errores) es “1 … 10”. pero no olvides usar un espacio entre el número y los puntos o el progtwig pensará que tu intervalo es un número y obtendrás un error “2 puntos decimales …”. Espero eso ayude.

 int score; int main() { cout<<"Enter score"<>score; switch(score){ case 100: cout<<"Your score is Perfect"< 

Las sentencias de mayúsculas y minúsculas son un sustituto de las sentencias long si que comparan una variable con varios valores “integrales” (los valores “integrales” son simplemente valores que se pueden express como un entero, como el valor de una char). La condición de una instrucción switch es un valor. El caso dice que si tiene el valor de lo que sea después de ese caso, haga lo que siga a los dos puntos. El descanso se usa para salir de las declaraciones de casos.

Por lo tanto, no puede usar tales declaraciones condicionales en el caso.

La estructura selectiva: cambiar

Esto es lo que funcionó para mí. dividiendo la marca por 10 y luego configurando el caso 10 y 9 para mostrar una “A” (esto mostrará una “A” para cualquier valor entre 90-100. Luego el caso 8 para mostrar “B”, entonces el caso 7 mostrará un ” C “para los valores de 70-79 y así sucesivamente.

 #include  using namespace std; main () { int mark; cout << "enter your mark: "; cin >> mark; switch (mark/10) { case 10: case 9: cout << "A"; break; case 8: cout << "B"; break; case 7: cout << "C"; break; case 6: cout << "D"; break; case 5: cout << "PASS"; break; default: cout << "FAIL"; break; } } 

Puedes hacer lo siguiente:

 //summarize the range to one value If score < 0 score = -1 switch(score){ case 1: //... break; case 2: //... break; case -1: //complete neg. range //... break; //... 

}

Esta es una forma que espero sea expresiva y simple de seguir.

Puede sorprenderle lo lejos que gcc / clang, etc. puede optimizar el código que genera. Yo esperaría que sea al menos tan eficiente como un interruptor / caja.

 #include  template struct switcher { constexpr switcher(Value const& value) : value_(value) {} constexpr switcher(Value const& value, bool enabled) : value_(value), enabled(enabled) {} template constexpr auto in_range(From&& from, To&& to, F&& f) { if (enabled and (from <= value_ and value_ <= to)) { f(); return switcher(value_, false); } else { return *this; } }; template constexpr auto otherwise(F&& f) { if (enabled) f(); } Value const& value_; const bool enabled = true; }; template constexpr auto decision(Value const& value) { return switcher(value); } void test(int x) { decision(x) .in_range(0, 10, [&] { std::cout << x << " maps to option A\n"; }) .in_range(11, 20, [&] { std::cout << x << " maps to option B\n"; }) .otherwise([&] { std::cout << x << " is not covered\n"; }); } int main(int argc, char **argv) { test(5); test(14); test(22); } 

Una idea potencialmente útil es que el switch acepta una expresión, por lo que puede doblar múltiples valores de entrada a una caja de conmutadores. Es muy feo, pero para su consideración:

 switch (score / 10) { case 10: cout << "a"; break; case 9: case 8: case 7: case 6: case 5: cout << "b"; break; case 4: case 3: cout << "c"; break; case 2: if (score >= 25) { cout << "c"; break; } // else fall through... case 1: cout << "d"; break; case 0: cout << (score > 0 ? "e" : "f"); break; default: cout << "BAD VALUE"; break; } 

Por supuesto, podría haber dividido entre 5 y tenía el case 4: (para 20-24) contra el case 5: (25-29) en lugar de un if dentro case 2: pero podría decirse que /10 es más intuitivo.

Sé que esta es una vieja pregunta, pero como las declaraciones de switch son en realidad envoltorios alrededor de tags, creo que el uso de goto puede ser (bueno) aquí.

  int value = 40; if (value < 10) { std::cout << "value < 10" << std::endl; goto end; } if (value < 50) { std::cout << "value < 50" << std::endl; goto end; } if (value > 30) { std::cout << "value > 30" << std::endl; goto end; } end: // resume 

De esta manera, puede omitir todo lo else y mantenerlo compacto. Deberías tener cuidado cuando usas goto aunque (en general).

¿Algo como esto?

 case 'A'..'Z' where a not in ['I','L','O']: 

Desafortunadamente, ningún comstackdor que conozco implementa esa extensión en particular, aunque GCC puede hacer rangos como otras respuestas señaladas. Para la portabilidad, puede cortar y pegar este fragmento de licencia DWTFYW. Si está utilizando una enumeración personalizada, puede recurrir a la generación de código para hacer algo similar.

 #define CASE_NUMBER \ case'0':case'1':case'2':case'3':case'4':\ case'5':case'6':case'7':case'8':case'9' #define CASE_ALPHA_LOWER \ case'a':case'b':case'c':case'd':\ case'e':case'f':case'g':case'h':\ case'i':case'j':case'k':case'l':\ case'm':case'n':case'o':case'p':\ case'q':case'r':case's':case't':\ case'u':case'v':case'w':case'x':\ case'y':case'z' #define CASE_ALPHA_UPPER \ case'A':case'B':case'C':case'D':\ case'E':case'F':case'G':case'H':\ case'I':case'J':case'K':case'L':\ case'M':case'N':case'O':case'P':\ case'Q':case'R':case'S':case'T':\ case'U':case'V':case'W':case'X':\ case'Y':case'Z' #define CASE_ALPHA CASE_ALPHA_UPPER:CASE_ALPHA_LOWER #define CASE_ALPHANUM CASE_ALPHA:CASE_NUMBER 

Si accede a GHCI, como la versión en línea en https://ghc.io/ , puede generar lo que necesita y pegarlo en un encabezado, por ejemplo

 foldl (++) "" ["case" ++ show x ++ ":" | x <- ['A'..'Z'], not $ x `elem` ['I','L','O']]