domingo, 18 de julio de 2010

Selección con el preprocesador

Después de hablar de las macros hace unos días, me he dedicado a investigar algo más sobre cómo funciona el preprocesador de C/C++. Está muy limitado, pero tiene algunas posibilidades.

Usando #if/#endif  es posible seleccionar parte de código, pero no podemos usar #if/#endif dentro de una macro. Es decir algo como esto no funciona

#define SELECCIONA(a,b,c)  #if a \

b \

#else \

c \

#endif

El motivo es que el preprocesador es muy tonto y sus comandos (que empiezan por #) sólo son reconocidos a principio de línea. Debido a que el \ a final de línea significa que se sigue en la siguiente línea como si fuera esta, la macro anterior sería equivalente a

#define SELECCIONA(a,b,c)  #if a b #else c #endif

Por lo que ni el #if ni el #else ni el #endif son reconocidos como comandos de preprocesador.

La solución es algo enrevesada, pero funciona y es usada en boost::preprocesor. Se basa en el concatenador de tokens. Es un operador especial (no es un comando) del preprocesador. Se escribe ##. El resultado de esta concatenación es agrupar dos identificadores en uno.

#define CONCATENA(a,b) a ## b

CONCATENA(hola, adios) //Equivalente a escribir    holaadios

Debido a que el preprocesador vuelve a expandir el resultado de sus macros, es fácil usar el siguiente truco para la selección.

#define IF_TRUE(t,e) t

#define IF_FALSE(t,e) e

#define IF(c,t,e) IF_##c (t, e)

IF(TRUE, bien, mal) //Se expande a IF_TRUE(bien,mal) y se vuelve a expandir a  bien

Ahora podemos combinar este truco con la técnica explicada hace unos días para crear código opcionalmente.

0 comentarios:

Publicar un comentario en la entrada