c++ - operaciones - operadores de bits java
¿Cuándo el operador<< se refiere al operador de inserción y cuándo al desplazamiento a la izquierda a nivel de bits? (6)
Esto dará como resultado 10, y el operador << se refiere al desplazamiento a la izquierda.
cout << ab () << aab << endl;
Esto se debe al hecho de que el orden de evaluación de los operandos no está especificado. Con clang da salida a 11, pero con gcc da salida a 10.
Tu codigo:
cout << a.b() << a.a.b << endl;
puede ser reemplazado con:
std::cout.operator<<(a.b()).operator<<(a.a.b);
clang primero evalúa ab()
luego aab
, g ++ lo hace al revés. Como tu ab()
modifica las variables, obtienes diferentes resultados.
Cuando reescribes tu código como:
cout << a.b();
cout << a.a.b ;
luego tiene dos declaraciones de expresiones completas, no hay ningún comportamiento no especificado aquí relacionado con la evaluación del operando. Entonces siempre obtienes el mismo resultado.
¿Cuándo el operator <<
refiere al operador de inserción y cuándo se refiere al desplazamiento a la izquierda a nivel de bits?
Esto dará como resultado 10
, y el operator <<
refiere al desplazamiento a la izquierda.
cout << a.b() << a.a.b << endl;
Y esto dará como resultado 11
, el operator <<
refiere al operador de inserción.
cout << a.b();
cout << a.a.b ;
Estoy confundido, ¿cuándo el operator <<
(cuando se usa con cout
) se referirá al operador de cambio a la izquierda?
#include <iostream>
using namespace std;
class A {
public:
A() { a.a = a.b = 1; }
struct { int a, b; } a;
int b();
};
int A::b(){
int x=a.a;
a.a=a.b;
a.b=x;
return x;
};
int main(){
A a;
a.a.a = 0;
a.b();
cout << a.b() << a.a.b << endl; // ?????
return 0;
}
El problema con el que se enfrenta no tiene que ver con el operador <<. En cada caso, se llama al operador de inserción.
Sin embargo, se enfrenta a un problema relacionado con el orden de evaluación en la línea de comandos.
cout << a.b() << a.a.b << endl;
La función ab()
tiene un efecto secundario. Intercambia los valores aaa y aab Por lo tanto, es evidente que se llama ab () antes o después de evaluar el valor ov aab
.
En C ++, el orden de evaluación no está especificado, vea cppreference.com para una discusión más detallada.
En su caso, todos los operator <<
s son operadores de inserción de flujo de salida porque su argumento izquierdo es de tipo ostream&
, y se agrupan de izquierda a derecha.
La diferencia en la salida se debe al orden de evaluación de los argumentos de la función:
cout << a.b() << a.a.b
es
operator<<(operator<<(cout, a.b()), a.a.b)
así que la salida depende de cuál de aab
o ab()
se evalúa primero. Esto no está especificado por el estándar actual (C ++ 14), por lo que también podría obtener 11
.
AFAIK en C ++ 17 11
será el único resultado válido para ambos casos porque impone una evaluación de izquierda a derecha de los parámetros de la función.
Actualización: esto parece no ser cierto, ya que el comité decidió (a partir de N4606 ) ir con la evaluación de parámetros de secuencia indeterminada mencionada en la parte inferior de P0145R2 . Ver [expr.call] / 5.
Update2: Ya que estamos hablando de operadores sobrecargados aquí, se aplica [over.match.oper] / 2 en N4606, que dice
Sin embargo, los operandos se secuencian en el orden prescrito para el operador integrado.
Entonces, de hecho, el orden de evaluación estará bien definido en C ++ 17. Este malentendido aparentemente ha sido predicho por los autores de P0145:
No creemos que tal no determinismo aporte ningún beneficio de optimización adicional sustancial, pero perpetúa la confusión y los peligros en torno al orden de las evaluaciones en las llamadas a funciones.
Esta llamada:
cout << a.b() << a.a.b << endl;
primero considerará:
cout << a.b()
que corresponden al operador de inserción y devuelve una referencia a cout. Así, la instrucción se convertirá en:
(returned reference to cout) << a.a.b
que nuevamente llamará al operador de inserción y así sucesivamente ...
Si tu instrucción fue:
cout << (a.b() << a.a.b) << endl;
la parte entre paréntesis se consideraría primero:
a.b() << a.a.b
esta vez, tiene un operador entre 2 int
: el compilador solo puede resolverlo como una llamada al operador de bitwise.
Los operadores binarios, como <<
, tienen dos propiedades que definen su uso: precedencia (operador) y asociatividad (izquierda o derecha). En este caso, la asociatividad es la clave y, ver, por ejemplo, http://en.cppreference.com/w/c/language/operator_precedence , el operador <<
tiene asociatividad de izquierda a derecha, por lo que están secuenciados (como si entre paréntesis) de izquierda a derecha:
((cout << a.b()) << a.a.b) << endl;
o en palabras secuenciadas como cout << ab()
luego << aab
y luego << endl
.
Después de esta secuencia, la sobrecarga del operador tiene efecto en cada invocación de <<
con los tipos dados, lo que determina la sobrecarga a la que se llama y, por lo tanto, si es una operación cout
o un turno.
Sin paréntesis, los operandos en ambos lados de la <<
determinan el significado: int << int == shift
, stream << any == insertion
. Esta ''reutilización'' del operador puede ser confusa, no es así. Pero puede resolver ambigüedades usando paréntesis: stream << (int << int) == "int"