ternario operador ejemplo condicional c++ language-lawyer operator-precedence conditional-operator

c++ - ejemplo - return operador ternario



¿Por qué el operador ternario con comas evalúa solo una expresión en el caso verdadero? (5)

Actualmente estoy aprendiendo C ++ con el libro C ++ Primer y uno de los ejercicios en el libro es:

Explica qué hace la siguiente expresión: someValue ? ++x, ++y : --x, --y someValue ? ++x, ++y : --x, --y

¿Qué sabemos? Sabemos que el operador ternario tiene mayor prioridad que el operador de coma. Con los operadores binarios esto fue bastante fácil de entender, pero con el operador ternario estoy luchando un poco. Con operadores binarios "tener mayor prioridad" significa que podemos usar paréntesis alrededor de la expresión con mayor prioridad y no cambiará la ejecución.

Para el operador ternario, haría:

(someValue ? ++x, ++y : --x, --y)

resultando efectivamente en el mismo código que no me ayuda a entender cómo el compilador agrupará el código.

Sin embargo, a partir de las pruebas con un compilador de C ++, sé que la expresión se compila y no sé qué podría representar un operador por sí mismo. Entonces el compilador parece interpretar el operador ternario correctamente.

Luego ejecuté el programa de dos maneras:

#include <iostream> int main() { bool someValue = true; int x = 10, y = 10; someValue ? ++x, ++y : --x, --y; std::cout << x << " " << y << std::endl; return 0; }

Resultados en:

11 10

Mientras que, por otro lado, con someValue = false imprime:

9 9

¿Por qué el compilador de C ++ generaría un código que para la rama verdadera del operador ternario solo incrementa x , mientras que para la rama falsa del ternario disminuye tanto x como y ?

Incluso fui tan lejos como poner paréntesis alrededor de la rama verdadera de esta manera:

someValue ? (++x, ++y) : --x, --y;

pero todavía resulta en 11 10 .


¿Por qué el compilador de C ++ generaría código que para la rama verdadera del operador ternario solo incrementa x

Usted malinterpretó lo que sucedió. La rama verdadera incrementa tanto x como y . Sin embargo, y se decrementa inmediatamente después de eso, incondicionalmente.

Así es como sucede esto: dado que el operador condicional tiene mayor prioridad que el operador de coma en C ++ , el compilador analiza la expresión de la siguiente manera:

(someValue ? ++x, ++y : --x), (--y); // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^

Tenga en cuenta el "huérfano" --y después de la coma. Esto es lo que lleva a disminuir y que se ha incrementado inicialmente.

Incluso fui tan lejos como poner paréntesis alrededor de la rama verdadera de esta manera:

someValue ? (++x, ++y) : --x, --y;

Estaba en el camino correcto, pero paréntesis de una rama incorrecta: puede solucionar esto al paréntesis de la rama else, de esta manera:

someValue ? ++x, ++y : (--x, --y);

Demostración (impresiones 11 11)


Como dijo @Rakete en su excelente respuesta, esto es complicado. Me gustaría agregar a eso un poco.

El operador ternario debe tener la forma:

¿lógica o expresión ? expresión : asignación-expresión

Entonces tenemos las siguientes asignaciones:

  • someValue : lógico o expresión
  • ++x, ++y : expresión
  • ??? ¿es la expresión de asignación --x, --y o solo --x ?

De hecho, solo es --x porque una expresión de asignación no puede analizarse como dos expresiones separadas por una coma (de acuerdo con las reglas gramaticales de C ++), por lo que --x, --y no puede tratarse como una expresión de asignación .

Lo que da como resultado que la porción de expresión ternaria (condicional) se vea así:

someValue?++x,++y:--x

Puede ser útil, en aras de la legibilidad, considerar que ++x,++y se calculen como si estuvieran entre paréntesis (++x,++y) ; algo contenido entre ? y : se secuenciará después del condicional. (Los paréntesis para el resto de la publicación).

y evaluado en este orden:

  1. someValue?
  2. (++x,++y) o --x (dependiendo del resultado de bool de 1.)

Esta expresión se trata como la --y izquierda de un operador de coma, siendo la --y derecha --y , así:

(someValue?(++x,++y):--x), --y;

Lo que significa que el lado izquierdo es una expresión de valor descartado , lo que significa que definitivamente se evalúa, pero luego evaluamos el lado derecho y devolvemos eso.

Entonces, ¿qué sucede cuando someValue es true ?

  1. (someValue?(++x,++y):--x) ejecuta e incrementa x e y para ser 11 y 11
  2. La expresión izquierda se descarta (aunque los efectos secundarios del incremento permanecen)
  3. Evaluamos el lado derecho del operador de coma: --y , que luego disminuye y nuevamente a 10

Para "arreglar" el comportamiento, puede agrupar --x, --y con paréntesis para transformarlo en una expresión primaria que es una entrada válida para una expresión de asignación *:

someValue?++x,++y:(--x, --y);

* Es una cadena larga bastante divertida que conecta una expresión de asignación a una expresión primaria:

asignación-expresión --- (puede consistir en) -> expresión condicional -> lógica-o-expresión -> lógica-y-expresión -> inclusiva-o-expresión -> exclusiva-o-expresión - -> y-expresión -> igualdad-expresión -> expresión-relacional -> desplazamiento-expresión -> expresión-aditiva -> expresión-multiplicativa -> expresión-pm -> expresión-cast -> expresión unaria -> expresión-postfix -> expresión-primaria


Su problema es que la expresión ternaria realmente no tiene mayor prioridad que la coma. De hecho, C ++ no se puede describir con precisión simplemente por precedencia, y es exactamente la interacción entre el operador ternario y la coma donde se descompone.

a ? b++, c++ : d++

se trata como:

a ? (b++, c++) : d++

(la coma se comporta como si tuviera mayor precedencia). Por otra parte,

a ? b++ : c++, d++

se trata como:

(a ? b++ : c++), d++

y el operador ternario tiene mayor prioridad.


Un punto que se ha pasado por alto en las respuestas (aunque se menciona en los comentarios) es que el operador condicional se usa invariablemente (¿previsto por diseño?) En el código real como un atajo para asignar uno de los dos valores a una variable.

Entonces, el contexto más amplio sería:

whatIreallyWanted = someValue ? ++x, ++y : --x, --y;

Lo cual es absurdo, por lo que los crímenes son múltiples:

  • El lenguaje permite efectos secundarios ridículos en una tarea.
  • El compilador no te advirtió que estabas haciendo cosas extrañas.
  • El libro parece estar centrado en preguntas "engañosas". Uno solo puede esperar que la respuesta en la parte de atrás sea "Lo que hace esta expresión es depender de casos extraños en un ejemplo artificial para producir efectos secundarios que nadie espera. Nunca haga esto".

Wow, eso es complicado.

El compilador ve tu expresión como:

(someValue ? (++x, ++y) : --x), --y;

El operador ternario necesita un : no puede sostenerse por sí mismo en ese contexto, pero después de eso, no hay ninguna razón por la cual la coma debe pertenecer al caso falso.

Ahora podría tener más sentido por qué obtienes esa salida. Si someValue es verdadero, entonces ++x , ++y y --y se ejecutan, lo que no cambia efectivamente y agrega uno a x .

Si someValue es falso, entonces --x y --y se ejecutan, disminuyéndolos por uno.