Plantillas frente a macros de preprocesador

En algún momento puede surgir la pregunta de si es posible utilizar sustituciones de macros para generar código De hecho, sí es posible. Por ejemplo, el conjunto de funciones Max puede representarse fácilmente como una macro:

#define MAX(V1,V2) ((V1) > (V2) ? (V1) : (V2))

No obstante, las macros tienen capacidades más limitadas (nada más que la sustitución de texto) y, por tanto, sólo se utilizan en casos sencillos (como el anterior).

Cuando se comparan macros y plantillas deben tenerse en cuenta las diferencias que se indican a continuación.

El preprocesador «expande» las macros y las sustituye en el texto fuente antes de iniciar la compilación. Al mismo tiempo, no hay información sobre los tipos de parámetros y el contexto en el que se sustituye el contenido de la macro. En concreto, la macro MAX no puede proporcionar una comprobación de que los tipos de los parámetros V1 y V2 son iguales, y también de que el operador de comparación '>' está definido para ellos. Además, si en el texto de un programa se encuentra una variable con el nombre MAX, el preprocesador intentará sustituirla por la «llamada» de la macro MAX y estará «descontento» con la ausencia de argumentos. Peor aún, estas sustituciones ignoran en qué espacios de nombres o clases se encuentra el token MAX: básicamente, cualquiera sirve.

A diferencia de las macros, las plantillas son manejadas por el compilador en términos de tipos de argumentos específicos y dónde se utilizan, por lo que proporcionan comprobaciones de compatibilidad de tipos (y aplicabilidad general) para todas las expresiones de una plantilla, así como vinculación contextual. Por ejemplo, podemos definir una plantilla de método dentro de una clase concreta.

Una plantilla con el mismo nombre puede definirse de forma diferente para distintos tipos si es necesario, mientras que una macro con un nombre determinado siempre se sustituye por la misma «implementación». Por ejemplo, en el caso de una función como MAX, podríamos definir una comparación para cadenas que no distinga entre mayúsculas y minúsculas.

Los errores de compilación debidos a problemas en las macros son difíciles de diagnosticar, especialmente si la macro consta de varias líneas, ya que la línea problemática con la «llamada» de la macro se resalta «tal cual», sin la versión expandida del texto, tal y como llegó del preprocesador al compilador.

Al mismo tiempo, las plantillas son elementos del código fuente con una forma ya preparada, tal y como entran en el compilador, por lo que cualquier error en ellas tiene un número de línea y una posición en la línea específicos.

Las macros pueden tener efectos secundarios, de los que hablamos en la sección Forma de #define como pseudo-función: si los argumentos de la macro MAX son expresiones con incrementos/decrementos, se ejecutarán dos veces.

No obstante, las macros también tienen algunas ventajas. Las macros son capaces de generar cualquier texto, no sólo construcciones correctas del lenguaje. Por ejemplo, con unas pocas macros, puede simular la instrucción switch para cadenas (aunque este enfoque no es recomendable).

En la biblioteca estándar, las macros se utilizan, en concreto, para organizar el tratamiento de los eventos en los gráficos (véase MQL5/Include/Controls/Defines.mqh: EVENT_MAP_BEGIN, EVENT_MAP_END, ON_EVENT, etc.). No funcionará en plantillas, pero la forma de organizar un mapa de eventos en macros, por supuesto, está lejos de ser la única y no es la más conveniente para la depuración. Es difícil depurar paso a paso (línea a línea) la ejecución de código en macros. Las plantillas, por el contrario, admiten la depuración en su totalidad.