while outside loop for example español python c++ loops for-loop break

outside - python break while loop



¿Hay un equivalente al bucle de Python "for... else" en C++? (12)

Python tiene una instrucción for interesante que le permite especificar una cláusula else .

En una construcción como esta:

for i in foo: if bar(i): break else: baz()

la cláusula else se ejecuta después del for , pero solo si el termina normalmente (no por un break ).

Me preguntaba si había un equivalente en C ++. ¿Puedo usar for ... else ?


Algo como:

auto it = foo.begin(), end = foo.end(); while ( it != end && ! bar( *it ) ) { ++ it; } if ( it != foo.end() ) { baz(); }

debería hacer el truco, y evita la break no estructurada.


Esta es mi implementación aproximada en C ++:

bool other = true; for (int i = 0; i > foo; i++) { if (bar[i] == 7) { other = false; break; } } if(other) baz();


No conozco una forma elegante de lograr esto en C / C ++ (sin involucrar una variable de indicador). Las otras opciones sugeridas son mucho más horribles que eso ...

Para responder a @Kerrek SB sobre usos de la vida real, encontré algunos en mi código (fragmentos simplificados)

Ejemplo 1: hallazgo / error típico

for item in elements: if condition(item): do_stuff(item) break else: #for else raise Exception("No valid item in elements")

Ejemplo 2: número limitado de intentos

for retrynum in range(max_retries): try: attempt_operation() except SomeException: continue else: break else: #for else raise Exception("Operation failed {} times".format(max_retries))


No existe tal construcción de lenguaje en C ++, pero, gracias a la "magia" del preprocesador, puedes hacer uno para ti. Por ejemplo, algo como esto (C ++ 11):

#include <vector> #include <iostream> using namespace std; #define FOR_EACH(e, c, b) auto e = c.begin(); for (; e != c.end(); ++e) {b} if (e == c.end()) {} int main() { vector<int> v; v.push_back(1); v.push_back(2); FOR_EACH(x, v, { if (*x == 2) { break; } cout << "x = " << *x << " "; }) else { cout << "else"; } return 0; }

Esto debería generar x = 1 else .

Si cambia if (*x == 2) { to if (*x == 3) { , la salida debe ser x = 1 x = 2 .

Si no le gusta el hecho de que se agrega una variable en el alcance actual, puede cambiarla levemente:

#define FOR_EACH(e, c, b, otherwise) {auto e = c.begin(); for (; e != c.end(); ++e) {b} if (e == c.end()) {} otherwise }

entonces el uso sería:

FOR_EACH(x, v, { if (*x == 2) { break; } cout << "x = " << *x << " "; }, else { cout << "else"; })

No es perfecto, por supuesto, pero, si se usa con cuidado, le ahorrará cierta cantidad de tipeo y, si se usa mucho, se convertiría en parte del "vocabulario" del proyecto.


No solo es posible en C ++, es posible en C. Me quedaré con C ++ para hacer que el código sea comprensible:

for (i=foo.first(); i != NULL || (baz(),0); i = i.next()) { if bar(i): break; }

Dudo que deje pasar una revisión del código, pero funciona y es eficiente. En mi opinión, también es más claro que algunas de las otras sugerencias.


Probablemente no haya una sola solución que se adapte mejor a todos los problemas. En mi caso, una variable de bandera y un bucle for basado for rango con un especificador auto funcionaron mejor. Aquí hay un equivalente del código en cuestión:

bool none = true; for (auto i : foo) { if (bar(i)) { none = false; break; } } if (none) baz();

Es menos tipado que usar iteradores . Especialmente, si usa el bucle for para inicializar una variable, puede usar eso en lugar del indicador booleano.

Gracias a auto escritura auto es mejor que std::none_of , si desea std::none_of la condición en lugar de call bar() (y si no está usando C ++ 14).

Tuve una situación donde ocurrieron ambas condiciones, el código se veía así:

for (auto l1 : leaves) { for (auto x : vertices) { int l2 = -1, y; for (auto e : support_edges[x]) { if (e.first != l1 && e.second != l1 && e.second != x) { std::tie(l2, y) = e; break; } } if (l2 == -1) continue; // Do stuff using vertices l1, l2, x and y } }

No hay necesidad de iteradores aquí, porque v indica si break produjo break corte.

Usar std::none_of requeriría especificar el tipo de elementos de support_edges[x] explícitamente en argumentos de una expresión lambda.


Puede usar for-else casi como en Python definiendo dos macros:

#define BREAK {CONTINUETOELSE = false; break;} #define FORWITHELSE(x, y) {bool CONTINUETOELSE = true; x if(!CONTINUETOELSE){} y}

Ahora coloque el for y el else dentro de la macro FORWITHELSE separados por una coma y use BREAK lugar de break . Aquí hay un ejemplo:

FORWITHELSE( for(int i = 0; i < foo; i++){ if(bar(i)){ BREAK; } }, else{ baz(); } )

Hay dos cosas que debe recordar: poner una coma antes que el else y usar BREAK lugar de break .


Puede usar una función lambda para esto:

[&](){ for (auto i : foo) { if (bar(i)) { // early return, to skip the "else:" section. return; } } // foo is exhausted, with no item satisfying bar(). i.e., "else:" baz(); }();

Esto debería comportarse exactamente como "por ... favor" de Python, y tiene algunas ventajas sobre las otras soluciones:

  • Es un verdadero reemplazo directo para "for..else": la sección "for" puede tener efectos secundarios (a diferencia de none_of, cuyo predicado no debe modificar su argumento), y tiene acceso al alcance externo.
  • Es más legible que definir una macro especial.
  • No requiere ninguna variable de bandera especial.

Pero ... usaría la variable de bandera torpe, yo mismo.


Respuesta directa: no, probablemente no puedas, o esté basado en el compilador, en el mejor de los casos. ¡PERO aquí hay un truco de una macro que funciona!

Algunas notas:

Usualmente programo con Qt, entonces estoy acostumbrado a tener un bucle foreach, y nunca tengo que lidiar con iteradores directamente.

Probé esto con el compilador de Qt (v 5.4.2) pero debería funcionar. Esto es asqueroso por varias razones, pero generalmente hace lo que usted quisiera. No apruebo la codificación de esta manera, pero no hay ninguna razón por la que no funcione, siempre que tenga cuidado con la sintaxis.

#include <iostream> #include <vector> #define for_else(x, y) __broke__ = false; for(x){y} if (__broke__) {} #define __break__ __broke__ = true; break bool __broke__; // A global... wah wah. class Bacon { public: Bacon(bool eggs); inline bool Eggs() {return eggs_;} private: bool eggs_; }; Bacon::Bacon(bool eggs) { eggs_ = eggs; } bool bar(Bacon *bacon) { return bacon->Eggs(); } void baz() { std::cout << "called baz/n"; } int main() { std::vector<Bacon *>bacons; bacons.push_back(new Bacon(false)); bacons.push_back(new Bacon(false)); bacons.push_back(new Bacon(false)); for_else (uint i = 0; i < bacons.size(); i++, std::cout << bacons.at(i)->Eggs(); if (bar(bacons.at(i))) { __break__; } ) else { baz(); } bacons.push_back(new Bacon(true)); bacons.push_back(new Bacon(false)); for_else (uint i = 0; i < bacons.size(); i++, std::cout << bacons.at(i)->Eggs(); if (bar(bacons.at(i))) { __break__; } ) else { baz(); } return EXIT_SUCCESS; }


Sí, puedes lograr el mismo efecto al:

auto it = std::begin(foo); for (; it != std::end(foo); ++it) if(bar(*it)) break; if(it == std::end(foo)) baz();


Si no le importa usar goto también se puede hacer de la siguiente manera. Este ahorra de extra if cheque y la declaración de variable de mayor alcance.

for(int i = 0; i < foo; i++) if(bar(i)) goto m_label; baz(); m_label: ...


Una forma más simple de expresar su lógica real es con std::none_of :

if (std::none_of(std::begin(foo), std::end(foo), bar)) baz();

Si se acepta la propuesta de rango para C ++ 17, con suerte se simplificará a:

if (std::none_of(foo, bar)) baz();