¿Cómo funciona el operador de coma en C ++?
Por ejemplo, si lo hago:
a = b, c;
¿A termina igualando b o c?
(Sí, sé que esto es fácil de probar, solo documente aquí para que alguien encuentre la respuesta rápidamente).
Actualización: esta pregunta ha expuesto un matiz al usar el operador de coma. Solo para documentar esto:
a = b, c; // a is set to the value of b!
a = (b, c); // a is set to the value of c!
Esta pregunta en realidad fue inspirada por un error tipográfico en el código. Lo que estaba destinado a ser
a = b;
c = d;
Convertido en
a = b, // <- Note comma typo!
c = d;
c++
comma-operator
Joe Schneider
fuente
fuente
a = (b, c);
.a = b, c = d;
realmente funciona igual que lo previstoa = b; c = d;
?b
yd
son evaluaciones de funciones que usan (y modifican) un estado común, el orden de ejecución no se define hastaC++17
.Respuestas:
Sería igual
b
.El operador de coma tiene una precedencia menor que la asignación.
fuente
Tenga cuidado al notar que el operador de coma puede estar sobrecargado en C ++. Por lo tanto, el comportamiento real puede ser muy diferente del esperado.
Como ejemplo, Boost.Spirit utiliza el operador de coma con bastante inteligencia para implementar inicializadores de lista para tablas de símbolos. Por lo tanto, hace que la siguiente sintaxis sea posible y significativa:
Tenga en cuenta que debido a la precedencia del operador, el código es (¡intencionalmente!) Idéntico a
Es decir, el primer operador llamado es el
keywords.operator =("and")
que devuelve un objeto proxy en el queoperator,
se invocan los s restantes :fuente
char[]
, que no se puede sobrecargar. El código llama intencionalmente primerooperator=
y luegooperator,
para cada elemento restante.El operador de coma tiene la precedencia más baja de todos los operadores C / C ++. Por lo tanto, siempre es el último en unirse a una expresión, lo que significa esto:
es equivalente a:
Otro hecho interesante es que el operador de coma introduce un punto de secuencia . Esto significa que la expresión:
está garantizado para tener sus tres subexpresiones ( a + b , c () y d ) evaluadas en orden. Esto es significativo si tienen efectos secundarios. Normalmente, los compiladores pueden evaluar subexpresiones en el orden que consideren adecuado; por ejemplo, en una llamada de función:
Los argumentos pueden ser evaluados en un orden arbitrario. Tenga en cuenta que las comas en la llamada a la función no son operadores; Son separadores.
fuente
,
tiene tan baja prioridad, que incluso va a la zaga en sí ;) ... Es decir: por comas como- operador tiene una prioridad más baja que comas como- separador . Entonces, si desea usar un operador de coma como operador dentro de un argumento de una sola función, asignación de variable u otra lista separada por comas , entonces debe usar paréntesis, por ejemplo:int a = 1, b = 2, weirdVariable = (++a, b), d = 4;
El operador de coma:
Se define una versión predeterminada del operador de coma para todos los tipos (incorporada y personalizada), y funciona de la siguiente manera: dado
exprA , exprB
:exprA
es evaluadoexprA
es ignoradoexprB
es evaluadoexprB
se devuelve como el resultado de toda la expresiónCon la mayoría de los operadores, el compilador puede elegir el orden de ejecución e incluso se debe omitir la ejecución si no afecta el resultado final (por ejemplo
false && foo()
, omitirá la llamadafoo
). Sin embargo, este no es el caso para el operador de coma y los pasos anteriores siempre sucederán * .En la práctica, el operador de coma predeterminado funciona casi de la misma manera que un punto y coma. La diferencia es que dos expresiones separadas por un punto y coma forman dos declaraciones separadas, mientras que la separación por comas mantiene todo como una sola expresión. Esta es la razón por la cual el operador de coma a veces se usa en los siguientes escenarios:
if( HERE )
for
buclefor ( HERE ; ; )
if (foo) HERE ;
(¡no haga eso, es realmente feo!)Cuando una declaración no es una expresión, el punto y coma no se puede reemplazar por una coma. Por ejemplo, estos no están permitidos:
(foo, if (foo) bar)
(if
no es una expresión)En su caso tenemos:
a=b, c;
, equivalente aa=b; c;
, suponiendo quea
sea de tipo que no sobrecargue el operador de coma.a = b, c = d;
equivalente aa=b; c=d;
, suponiendo quea
sea de tipo que no sobrecargue el operador de coma.Tenga en cuenta que no todas las comas son en realidad un operador de coma. Algunas comas que tienen un significado completamente diferente:
int a, b;
--- la lista de declaración de variables está separada por comas, pero estos no son operadores de comaint a=5, b=3;
--- esta también es una lista de declaración de variables separadas por comasfoo(x,y)
--- lista de argumentos separados por comas. De hecho, ¡x
yy
se puede evaluar en cualquier orden!FOO(x,y)
--- lista de argumentos macro separados por comasfoo<a,b>
--- lista de argumentos de plantilla separados por comasint foo(int a, int b)
--- lista de parámetros separados por comasFoo::Foo() : a(5), b(3) {}
--- lista de inicializadores separados por comas en un constructor de clase* Esto no es del todo cierto si aplica optimizaciones. Si el compilador reconoce que cierto código no tiene absolutamente ningún impacto en el resto, eliminará las declaraciones innecesarias.
Lectura adicional: http://en.wikipedia.org/wiki/Comma_operator
fuente
operator ,
está sobrecargado, pierde cualquier garantía de asociatividad (al igual que pierde las propiedades de cortocircuito deloperator&&
yoperator||
si están sobrecargados)?a, b, c
siempre significa(a, b), c
y nuncaa, (b, c)
. La última interpretación podría incluso conducir a un error de compilación si los elementos son de diferentes tipos. ¿Qué puede estar buscando es el orden de evaluación de los argumentos? No estoy seguro de eso, pero quizás tenga razón: podría suceder quec
se evalúe antes(a, b)
incluso si la coma es asociativa a la izquierda.struct Foo { Foo() : a(5), b(3) {} int b; int a; }
evacuab(3)
antesa(5)
. Esto es importante si su lista es de esta manera:Foo() : a(5), b(a) {}
. b no se establecerá en 5, sino más bien el valor no inicializado de a, sobre el cual su compilador puede advertir o no.El valor de
a
seráb
, pero el valor de la expresión serác
. Es decir, ena sería igual a
b
, yd
sería igual ac
.fuente
a = b; d = c;
?El valor de b se asignará a a. No le pasará nada a c
fuente
El valor de a será igual a b, ya que el operador de coma tiene una precedencia menor que el operador de asignación.
fuente
Sí, el operador de coma tiene poca prioridad que el operador de asignación
Salida: i = 3
Porque el operador de coma siempre devuelve el valor más a la derecha.
En caso de operador de coma con operador de asignación:
Salida: i = 1
Como sabemos, el operador de coma tiene menor prioridad que la asignación .....
fuente
i = 1;
en esa línea?Primero lo primero: la coma en realidad no es un operador, para el compilador es solo un token que adquiere un significado en contexto con otros tokens.
¿Qué significa esto y por qué molestarse?
Ejemplo 1:
Para comprender la diferencia entre el significado del mismo token en un contexto diferente, veamos este ejemplo:
Por lo general, un principiante C ++ podría pensar que esta expresión podría / sería comparar las cosas, pero es absolutamente incorrecto, el significado de la
<
,>
y,
fichas de depent en el contexto de uso.La interpretación correcta del ejemplo anterior es, por supuesto, que es una instancia de una plantilla.
Ejemplo 2
Cuando escribimos un bucle típicamente for con más de una variable de inicialización y / o más de una expresión que debe hacerse después de cada iteración del bucle, también usamos una coma:
El significado de la coma depende del contexto de uso, aquí es el contexto de la
for
construcción.¿Qué significa realmente una coma en contexto?
Para complicarlo aún más (como siempre en C ++), el operador de coma puede sobrecargarse (gracias a Konrad Rudolph por señalarlo).
Para volver a la pregunta, el Código
significa para el compilador algo como
porque la prioridad del
=
token / operador es mayor que la prioridad del,
token.y esto se interpreta en contexto como
(tenga en cuenta que la interpretación depende del contexto, aquí no se trata de una llamada a función / método o una instauración de plantilla).
fuente