Equivalencia de “a @ = b” y “a = a @ b”

A menudo es discutido (de hecho, creo que incluso el estándar alude a él), que a @= b y a = a @ b son equivalentes. Aquí estoy usando @ para representar un rango de símbolos como & y ^ .

Sin embargo, dudo que sean equivalentes en tiempo de ejecución, especialmente si a es un tipo atómico . Por ejemplo:

 std::atomic_int a; a ^= 1; 

(que es una forma atómica de alternar a ) se plantea como equivalente a

 a = a ^ 1; 

Pero, esta segunda forma no es atómica debido a la asignación.

Por lo tanto, dudo que su equivalencia literal y un comstackdor (independientemente de lo que diga el estándar) no sea capaz de cambiar la forma más corta a la más larga.

¿Estoy en lo correcto?

El estándar de idioma solo define el comportamiento de los operadores integrados, no las sobrecargas “definidas por el usuario”. Y desde el punto de vista del idioma, no hay un operador integrado para std::atomic_int (que es formalmente un “tipo definido por el usuario”); std::atomic_int es un typedef para std::atomic , que define un número de operator@= sobrecargas, pero no simples @ . Entonces para

 std::atomic_int i; i ^= 1; 

La segunda línea se convierte en:

 i.operator^=( 1 ); 

pero para:

 std::atomic_int i; i = i ^ 1; 

La segunda línea se convierte en:

 i.operator=( i.operator int() ^ 1 ); 

Se podría argumentar que esto es parte de lo que implica “el argumento de la mano izquierda que se evalúa dos veces, en lugar de una vez”. Sin embargo, de manera más general, las definiciones de operadores sobrecargados son lo que el autor del operador quería: operator+= podría (en lo que concierne al idioma) sustraer, incluso cuando se agrega operator+ . (Tengo un par de casos en los que operator+ realmente operator+= . Esto no suele ser una buena idea, y en mi caso, solo ocurre con clases especialmente diseñadas para su uso con std::accumulate , y documentadas para ser utilizadas únicamente en ese caso.) El estándar simplemente no restringe los operadores definidos por el usuario

Estás en lo correcto. En realidad, ni siquiera se garantiza que sean equivalentes en el caso general no atómico, ya que una clase podría proporcionar diferentes sobrecargas para += y + que son completamente independientes.

Los operadores integrados tienen esa equivalencia, excepto que a @= b solo evalúa a once, mientras que a = a @ b evalúa dos veces.

Sin embargo, estos no son los operadores integrados, sino las sobrecargas proporcionadas por la biblioteca estándar. Se tratan como funciones separadas, no relacionadas, por lo que el comstackdor no puede cambiar una por otra. (De hecho, como se señala en los comentarios, solo los operadores de asignación están sobrecargados para los tipos atómicos, tendría que cargar y almacenar explícitamente el valor para usar la forma no atómica).

Puedes definir ^= y ^ para hacer cosas completamente diferentes. Por lo tanto, ningún comstackdor puede cambiar uno por otro solo si quiere