Muestra las diferencias entre dos versiones de la página.
Ambos lados, revisión anterior Revisión previa Próxima revisión | Revisión previa Próxima revisión Ambos lados, revisión siguiente | ||
cpp-avanzado:macros [2017/12/05 22:30] santo |
cpp-avanzado:macros [2023/11/29 15:01] santo |
||
---|---|---|---|
Línea 29: | Línea 29: | ||
#define dforall(i,c) for(auto i = (c).rbegin(); i != (c).rend(); i++) | #define dforall(i,c) for(auto i = (c).rbegin(); i != (c).rend(); i++) | ||
</code> | </code> | ||
+ | |||
+ | La siguiente sirve para evitar montones de errores peligrosos y muy difíciles de detectar producto de comparar enteros con y sin signo, ya que ''.size()'' retorna un entero sin signo, por lo que al hacerle cuentas resultados como ''-1'' automáticamente pasan a $2^{bits}-1$. El ejemplo más común sería escribir algo como ''if (v.size()-1 >= 0)'', que da siempre ''true'', a diferencia de ''if (SIZE(v)-1 >= 0)'' que se comporta como uno espera. Pasar inmediatamente a entero con signo evita problemas. | ||
+ | <code cpp> | ||
+ | #define SIZE(c) int((c).size()) | ||
+ | </code> | ||
+ | |||
+ | |||
La siguiente es muy útil para utilizar con funciones de STL, donde se suele pedir un rango mediante dos iteradores, para pasar directamente una colección completa. | La siguiente es muy útil para utilizar con funciones de STL, donde se suele pedir un rango mediante dos iteradores, para pasar directamente una colección completa. | ||
<code cpp> | <code cpp> | ||
- | #define all(c) (c).begin(),(c).end() | + | #define ALL(c) begin(c), end(c) |
</code> | </code> | ||
- | El uso más común de esta macro, es para llamar a la función ''sort'', con ''sort(all(v))'' por ejemplo, siendo ''v'' un [[:curso-cpp:contenedor-vector|vector]]. Sin embargo es útil con muchísimas funciones de la [[cpp-avanzado:stl:|STL]], como podría ser por ejemplo una instrucción ''find(all(v), 27)''. | + | El uso más común de esta macro, es para llamar a la función ''sort'', con ''sort(ALL(v))'' por ejemplo, siendo ''v'' un [[:curso-cpp:contenedor-vector|vector]]. Sin embargo es útil con muchísimas funciones de la [[cpp-avanzado:stl:|STL]], como podría ser por ejemplo una instrucción ''find(ALL(v), 27)''. |
La siguiente sirve para consultar si un elemento está en un [[:cpp-avanzado:set|set]] (o [[:cpp-avanzado:map|map]]: en un map, se consulta si el elemento dado es una **clave** del diccionario). | La siguiente sirve para consultar si un elemento está en un [[:cpp-avanzado:set|set]] (o [[:cpp-avanzado:map|map]]: en un map, se consulta si el elemento dado es una **clave** del diccionario). | ||
<code cpp> | <code cpp> | ||
- | #define esta(x,c) ((c).find(x) != (c).end()) | + | #define ESTA(x,c) ((c).find(x) != (c).end()) |
</code> | </code> | ||
Línea 72: | Línea 79: | ||
<code cpp> | <code cpp> | ||
forn(i, 10){ | forn(i, 10){ | ||
- | forn (j, v.size()) { | + | forn (j, SIZE(v)) { |
} | } | ||
} | } | ||
</code> | </code> | ||
- | |||
- | (Comentario: que en la declaración de la macro hay un int(n) que nos permite que el forn hasta v.size() no tenga un posible bug por ser este valor de tipo unsigned, y de paso logra que el compilador no emita un warning por esto.) | ||
Uno podría entusiarmarse con las macros y hacer la siguiente macro: | Uno podría entusiarmarse con las macros y hacer la siguiente macro: | ||
Línea 86: | Línea 91: | ||
</code> | </code> | ||
- | **Es una mala idea** definir el ''forn'' sin pasarle la variable para indexar, porque eso nos podria introducir "bugs ocultos" por no ser suficientemente declarativos y esconder cosas en la macro. En este caso, **escondemos una declaración de variables**. | + | **Es una muy mala idea** definir el ''forn'' sin pasarle la variable para indexar, porque eso nos podría introducir muy fácilmente "bugs ocultos" por no ser suficientemente declarativos y esconder cosas en la macro. En este caso, **escondemos una declaración de variables visibles fuera de la macro**. |
Por ejemplo, este código tendría un error oculto usando esa macro | Por ejemplo, este código tendría un error oculto usando esa macro | ||
Línea 99: | Línea 104: | ||
En general **el objetivo de las macros no es escribir menos caracteres, sino escribir código que evite bugs** simples por repetición o copy-paste. | En general **el objetivo de las macros no es escribir menos caracteres, sino escribir código que evite bugs** simples por repetición o copy-paste. | ||
+ | |||
+ | Otro ejemplo: | ||
<code cpp> | <code cpp> | ||
Línea 108: | Línea 115: | ||
</code> | </code> | ||
- | Ese código tiene un bug no evidente, en el segundo for incrementa i en vez de j. | + | Ese código tiene un bug no evidente a simple vista: en el segundo for incrementa i en vez de j. |
En cambio, usando la macro forn como la definimos más arriba, sería | En cambio, usando la macro forn como la definimos más arriba, sería | ||
Línea 119: | Línea 126: | ||
</code> | </code> | ||
- | ¡Donde ese bug es simplemente **imposible** de escribir! | + | ¡Donde ese bug es simplemente **imposible** de escribir! Usar ''i'' ambas veces sería el bug más parecido, pero si usamos las [[:cpp-avanzado:opciones-gcc|opciones de compilación]] recomendadas tendremos un warning por shadow al hacerlo, y es un bug mucho más fácil de detectar. |