2012-08-27 17 views
7

¿Qué está pasando aquí?¿Cuál es la precedencia del operador de coma dentro del operador condicional en C++?

#include <iostream> 
using namespace std; 

int main(){ 

    int x=0,y=0; 
    true? ++x, ++y : --x, --y; 
    cout << "x: " << x << endl; 
    cout << "y: " << y << endl; //why does y=0 here? 

    x=0,y=0; 
    false ? ++x, ++y : --x, --y; 
    cout << "x: " << x << endl; 
    cout << "y: " << y << endl; 
} 

x: 1 
y: 0 

x: -1 
y: -1 

El segundo caso parece estar bien. Espero que tanto x como y aumenten a 1 en el primer caso, pero solo se incrementa el operando de la mano izquierda.

+0

Indique el código que realmente se compila; de lo contrario, no me molestaré en ayudarlo –

+0

'++ y' sucede, pero luego' -y' sí. ¿verdad? ++ x, ++ y: --x, --y' se analiza como '(true? ++ x, ++ y: --x), --y' – oldrinb

+0

@AdrianCornish Este código se compila; ¿Lo intentaste? – chrisaycock

Respuesta

17

El primero es equivalente a:

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

El segundo es equivalente a:

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

Así, el --y siempre se ejecuta. En la primera línea, los incrementos se ejecutan primero, por lo que se espera x = 1, y = 0. En la segunda línea, se ejecuta primero el decremento de x, por lo que se espera x = -1, y = -1.


Como se señaló en un comentario (a otra respuesta) por Barmar:

Y por si alguien se pregunta por qué la coma entre ++x y ++y no tiene el mismo efecto, es porque (true? ++x) no sería válido en absoluto. Por lo que el compilador mantiene la exploración hasta que encuentra el :, pero más allá de que se detiene cuando llega a un operador de menor prioridad [(, en este ejemplo) o al final de la declaración].

+1

Para expresar su párrafo final con más precisión: la precedencia (y la asociatividad) de los operadores solo afecta al enlace de los operandos a la izquierda y a la derecha del operador, no al del medio. Por supuesto, el operador ternario es el único que tiene un operando intermedio en primer lugar. Pero a lo largo de estas líneas uno podría considerar un par de paréntesis como unario (identidad) operador cuyo único operando está en el medio (entre los "símbolos de operador"), lo que explicaría por qué la agrupación que logra no se ve afectada por ninguna regla de precedencia. –

0

Leer el estándar

§5.18 operador coma [expr.comma]

¶1 Los grupos operador coma de izquierda a derecha.

expression: 
assignment-expression 
expression , assignment-expression 

Un par de expresiones separadas por una coma se evalúa de izquierda a derecha; la expresión izquierda es una expresión de valor descartado (Cláusula 5). Cada valor de la computación y los efectos secundarios asociados con la expresión izquierda se secuencia antes de cada efecto del valor de cálculo y secundario asociado con la expresión adecuada. El tipo y el valor del resultado son el tipo y el valor del operando correcto; el resultado es de la misma categoría de valor como su operando derecho, y es un campo de bits si su operando derecho es un glvalue y un campo de bit.

¶2 En contextos donde a la coma se le da un significado especial, [Ejemplo: en listas de argumentos a funciones (5.2.2) y listas de inicializadores (8.5) -ejemplo] el operador de coma como se describe en la Cláusula 5 puede aparecer solo entre paréntesis. [Ejemplo:

f(a, (t=3, t+2), c); 

tiene tres argumentos, el segundo de los cuales tiene el valor 5. -end ejemplo]

+0

Gracias por la edición ordenada Jon –

+0

Gracias. ¿cierto? (++ x, ++ y): (--x, --y); fijo. Lección: siempre use paréntesis donde la intención no es trivial. – hhbilly

+2

@ user1626720 - sin mencionar "no abuse del operador ternario". El código en cuestión debe escribirse con if ... else, ya que el valor del operador ternario se descarta. –

4

El y es cero porque coma tiene the lowest precedence among all C++ operators.Como su precedencia es menor que la del operador condicional ternario, los operadores condicionales se analizan como true? ++x, ++y : --x y false? ++x, ++y : --x. En ambos casos, la instrucción --y se ejecuta incondicionalmente.

EDITAR La primera coma es diferente ya que el compilador ha encontrado un ?, por lo que ahora se necesita un : para completar el "cuando la verdadera" expresión de la condicional. Es por eso que se aceptan ++x y ++y.

+3

Y en caso de que alguien se pregunte por qué la coma entre '++ x' y' ++ y' no tiene el mismo efecto, es porque '(true? ++ x)' no sería válida en absoluto. Entonces sigue escaneando hasta que encuentra el ':', pero más allá de eso se detiene cuando llega a un operador de precedencia más baja. – Barmar

+1

Ah, y nunca lo haga 'if (x == 100,000)' aprendí de la manera más dura ;-) –