Operador ternario condicional

El operador ternario condicional permite describir en una sola expresión dos opciones de cálculo basadas en una condición determinada. La sintaxis del operador es la siguiente

condition ? expression_true : expression_false

La condición lógica debe especificarse en el primer operando 'condition' y puede ser una combinación arbitraria de operaciones de comparación y operaciones lógicas normales. Ambas ramas deben estar presentes.

Si la condición es verdadera, se calculará la expresión expression_true, mientras que si es falsa, se calculará expression_false.

Este operador garantiza que sólo se ejecute una de las expresiones expression_true y expression_false.

Los tipos de las dos expresiones deben ser idénticos; de lo contrario, se producirá un intento de conversión sus tipos de forma implícita.

Tenga en cuenta que el resultado de procesar expresiones en MQL5 siempre representa un RValue (en C++, si sólo hay LValues en las expresiones, entonces el resultado del operador también será LValue). Así, el siguiente código se compila bien en C++, pero da un error en MQL5:

int x1y1; ++(x1 > y1 ? x1 : y1); // '++' - l-value required

Los operadores condicionales pueden anidarse, es decir, se permite utilizar otro operador condicional como condición o cualquiera de las ramas (expression_true o expression_false). Al mismo tiempo, no siempre puede quedar claro a qué se refieren las condiciones (si no se utilizan paréntesis para denotar explícitamente la agrupación). Veamos algunos ejemplos en ExprConditional.mq5.

int x = 1y = 2z = 3p = 4q = 5f = 6h = 7;
int r0 = x > y ? z : p != 0 && q != 0 ? f / (p + q) : h// 0 = f / (p + q)

En este caso, la primera condición lógica representa la comparación x > y. Si es verdadero, se ejecuta la rama con la variable z. Si es falso, se comprueba la condición lógica adicional p != 0 && q != 0, también con dos opciones de expresión.

A continuación se muestran algunos operadores más en los que las condiciones lógicas se escriben en mayúsculas, mientras que las opciones de cálculo se escriben en minúsculas. Para simplificar, todas ellas se convierten en variables (del ejemplo anterior). En realidad, cada uno de los tres componentes puede ser una expresión más rica.

Para cada cadena puede hacer un seguimiento de cómo se obtiene el resultado, lo que se ha mostrado en el comentario.

bool A = falseB = falseC = true;
int r1 = A ? x : C ? p : q;                              // 4
int r2 = A ? B ? x : y : z;                              // 3
int r3 = A ? B ? C ? p : q : y : z;                      // 3
int r4 = A ? B ? x : y : C ? p : q;                      // 4
int r5 = A ? f : h ? B ? x : y : C ? p : q;              // 2

Dado que el operador es asociativo a la derecha, la expresión compuesta se analiza de derecha a izquierda, es decir, la estructura situada más a la derecha con tres operandos combinados por '?' y ':' se convierte en el operando de la condición externa escrita a la izquierda. A continuación, teniendo en cuenta esta sustitución, se vuelve a analizar la expresión de derecha a izquierda, y así sucesivamente, hasta obtener la estructura final completa de nivel superior '?:'.

Por lo tanto, las expresiones anteriores se agrupan de la siguiente manera (los paréntesis denotan la interpretación implícita del compilador, pero dichos paréntesis podrían añadirse a las expresiones para visualizar el código fuente, que es el enfoque que, de hecho, se recomienda):

int r0 = x > y ? z : ((p != 0 && q != 0) ? f / (p + q) : h);
int r1 = A ? x : (C ? p : q); 
int r2 = A ? (B ? x : y) : z
int r3 = A ? (B ? (C ? p : q) : y) : z
int r4 = A ? (B ? x : y) : (C ? p : q); 
int r5 = (A ? f : h) ? (B ? x : y) : (C ? p : q); 

Para la variable r5, la primera condición A ? f : h calcula la condición lógica para la expresión subsiguiente y, por lo tanto, se transforma en bool. Como A es igual a false, el valor se toma de la variable h. No es igual a 0; por lo tanto, la primera condición se considera verdadera. El resultado es la rama actuadora (B ? x : y), de la que se devuelve el valor de la variable y, ya que B es igual a false.

Deben estar los 3 componentes (una condición y 2 alternativas) en el operador. De lo contrario, el compilador generará el error «token inesperado»:

// ';' - unexpected token
// ';' - ':' colon sign expected
int r6 = A ? B ? x : y// lack of alternative

En el lenguaje del compilador, un token es un fragmento indivisible del código fuente que tiene un significado o propósito independiente, como tipo, identificador, carácter de puntuación, etc. El compilador divide todo el código fuente en una secuencia de tokens. Los signos de los operadores considerados también son tokens. En el código anterior hay dos símbolos '?' y debe haber dos símbolos ':' que se correspondan con ellos, pero solo hay uno. Por lo tanto, el compilador «dice» que el símbolo de fin de sentencia ';' es prematuro y «pregunta» qué es exactamente lo que es deficiente: «signo de dos puntos esperado».

Dado que el operador condicional tiene una prioridad muy baja (13 en la tabla completa, véase Prioridades de las operaciones), se recomienda encerrarlo entre paréntesis. Esto facilita evitar situaciones en las que los operandos de un operador condicional podrían ser «atrapados» por operaciones vecinas que tengan prioridades más altas. Por ejemplo, si necesitamos calcular el valor de una determinada variable w mediante la suma de dos operadores ternarios, un planteamiento sencillo podría ser el siguiente:

int w = A ? f : h + B ? x : y;                           // 1

Esto funcionará de forma diferente a lo que habíamos pensado. Debido a su mayor prioridad, la suma h + B se considera una única expresión. Considerando su análisis sintáctico de derecha a izquierda, esta suma aparece como una condición y se convierte al tipo bool, lo que incluso es advertido por el compilador como «expresión no booleana». La interpretación del compilador puede visualizarse incluso mediante paréntesis:

int w = A ? f : ((h + B) ? x : y);                       // 1

Para resolver el problema debemos colocar los paréntesis a nuestra manera.

int v = (A ? f : h) + (B ? x : y);                       // 9

El anidamiento profundo de operadores condicionales afecta negativamente a la comprensibilidad del código. Deben evitarse los niveles de anidamiento superiores a dos o tres.