¿Qué hace el operador unario plus?

¿Qué hace el operador unario plus? Hay varias definiciones que he encontrado ( aquí y aquí ) pero todavía no tengo idea para qué se usaría. Parece que no hace nada pero tiene un motivo, ¿no?

Está allí para ser sobrecargado si sientes la necesidad; para todos los tipos predefinidos es esencialmente un no-op.

Los usos prácticos de un operador aritmético unario no operativo son bastante limitados, y tienden a relacionarse con las consecuencias de usar un valor en una expresión aritmética, en lugar de hacerlo con el operador mismo. Por ejemplo, se puede usar para forzar el ensanchamiento de tipos integrales más pequeños a int , o asegurar que el resultado de una expresión se trate como un valor r y, por lo tanto, no sea compatible con un parámetro de referencia no const . Sin embargo, afirmo que estos usos son más adecuados para codificar el golf que la legibilidad. 🙂

En realidad, unario plus hace algo, incluso en C. Realiza las conversiones aritméticas habituales en el operando y devuelve un nuevo valor, que puede ser un número entero de mayor ancho. Si el valor original era un entero sin signo de menor ancho que int , también se cambiará a un valor signed .

Por lo general, esto no es tan importante, pero puede tener un efecto, por lo que no es una buena idea usar unario plus como una especie de “comentario” que denota que un entero es positivo. Considere el siguiente progtwig C ++:

 void foo(unsigned short x) { std::cout << "x is an unsigned short" << std::endl; } void foo(int x) { std::cout << "x is an int" << std::endl; } int main() { unsigned short x = 5; foo(+x); } 

Esto mostrará "x is an int".

Entonces, en este ejemplo, unario plus creó un nuevo valor con un tipo diferente y firmado.

Lo he visto utilizado para mayor claridad, para enfatizar el valor positivo como algo distinto de un valor negativo:

 shift(+1); shift(-1); 

Pero ese es un uso bastante débil. La respuesta es definitivamente sobrecarga.

De la segunda edición de K & R:

El unario + es nuevo con el estándar ANSI. Fue agregado por simetría con el unario -.

Una cosa que el built-in unary + hace es convertir lvalue en un rvalue. Por ejemplo, puedes hacer esto

 int x; &x; 

pero no puedes hacer esto

 &+x; 

🙂

PS “Sobrecarga” definitivamente no es la respuesta correcta. Unary + fue heredado de C y no hay sobrecarga de operador a nivel de usuario en C.

Lo principal unario + es la promoción de tipo a un int para tipos de datos más pequeños que int. Esto puede ser muy útil si intenta imprimir datos de char utilizando std::cout como datos numéricos.

 char x = 5; std::cout << +x << "\n"; 

es muy diferente de

 char x=5; std::cout << x << "\n"; 

También está disponible para sobrecargar, pero en la práctica su sobrecarga debería ser casi un NOP.

Si alguna vez necesita imprimir el valor numérico de los bytes sin procesar (por ejemplo, pequeños números almacenados como char) para la depuración o cualquier otra razón, unary + puede simplificar el código de impresión. Considerar

 char c = 42; cout << c << endl; // prints "*\n", not what you want in this case cout << (int)c << endl; // prints "42\n", ok cout << +c << endl; // prints "42\n", much easier to type 

Este es solo un ejemplo rápido. Estoy seguro de que hay otras ocasiones en que unario + puede ayudar a tratar sus bytes más como números en lugar de texto similar.

No mucho. El argumento general para permitir la sobrecarga del operator+() es que definitivamente hay usos en el mundo real para sobrecargar el operator-() , y sería muy extraño (o asimétrico) si permitiera que el operator-() sobrecarga- operator-() pero no el operator+()

Creo que primero leí este argumento de Stroustrop, pero no tengo mis libros correctos para verificarlo. Podría estar equivocado.

Unary plus estuvo presente en C, donde no hizo absolutamente nada (al igual que la palabra clave auto ). Para no tenerlo, Stroustrup habría tenido que introducir una incompatibilidad gratuita con C.

Una vez que estaba en C ++, era natural permitir una función de sobrecarga, al igual que unario negativo, y Stroustrup podría haberlo introducido por esa razón si no estuviera ya allí.

Entonces, no significa nada. Se puede usar como una especie de decoración para hacer que las cosas se vean más simétricas, usando +1.5 como opuesto a -1.5, por ejemplo. En C ++, puede estar sobrecargado, pero va a ser confuso si el operator+() hace algo. Recuerde la regla estándar: al sobrecargar operadores aritméticos, haga cosas como int s do.

Si está buscando una razón por la cual está allí, encuentre algo sobre la historia temprana de C. Sospecho que no había una buena razón, ya que C no estaba realmente diseñado. Considere la palabra clave auto inútil (presumiblemente en contraste con la static , ahora se recicla en C ++ 0x), y la palabra clave de entry , que nunca hizo nada (y luego se omite en C90). Hay un correo electrónico famoso en el que Ritchie o Kernighan dicen que, cuando se dieron cuenta de que la precedencia del operador tenía problemas, ya había tres instalaciones con miles de líneas de código que no querían romper.

Un tidbit histórico. El comité de estandarización C99 también pensó que los usos existentes de plus unario eran bastante raros, como lo demuestra su consideración de reutilizarlo para lograr otra característica en el lenguaje: inhibición de la evaluación del tiempo de traducción de las expresiones constantes de coma flotante. Consulte la siguiente cita de C Justificación, sección F.7.4:

Una versión temprana de esta especificación permitió la aritmética de la constante del tiempo de traducción, pero habilitó el operador unario +, cuando se aplica a un operando, para nhibernate la evaluación del tiempo de traducción de las expresiones constantes.

Al final, la semántica se invirtió, con la evaluación del tiempo de ejecución impuesta en la mayoría de los contextos (al menos hasta la regla “como si”) y la capacidad de aplicar la evaluación del tiempo de traducción mediante el uso de inicializadores estáticos. Tenga en cuenta que la principal diferencia radica en la aparición de excepciones de coma flotante y otros ajustes de precisión o redondeo de punto flotante, cuando están presentes.

No puedo citar ninguna fuente para esto, pero he llegado a entender que es para promoción de tipo explícita, lo que implica conversión de tipo sin pérdida. Eso lo coloca en la parte superior de la jerarquía de conversión,

  • Promoción: new_type operator+(old_type)
  • Conversión: new_type(old_type)
  • Cast: operator(new_type)(old_type)
  • Coerción: new_type operator=(old_type)

Por supuesto, eso es de mi interpretación de una nota en uno de los manuales microsoft (realmente antiguos) c / c ++ que leí hace unos 15 años, así que tómalo con un grano de sal.

 #include  int main() { unsigned short x = 5; printf ("%d\n",sizeof(+x)); printf ("%d\n",sizeof(x)); return 0; } 

Como se muestra en el ejemplo anterior, el unario + realmente cambia el tipo, tamaño 4 y 2 respectivamente. Es extraño que la expresión + x de hecho se calcule en el tamaño de, pensé que no se suponía que lo hiciera. Tal vez se deba al hecho de que sizeof tiene la misma prioridad que el unario +.

Supongo que podrías usarlo para hacer siempre un número positivo. Simplemente sobrecargue el operador unario + para que sea abs. No merece la pena confundir a tus compañeros desarrolladores, a menos que realmente quieras ofuscar tu código. Entonces funcionaría bien.

EDITAR Reescribió por completo, porque me quedé sin respuesta en mi respuesta original.

Esto debería permitirle manejar la statement explícita de su tipo como un valor positivo (creo que en la mayoría de las operaciones no matemáticas). Parece que la negación sería más útil, pero supongo que aquí hay un ejemplo de dónde podría marcar la diferencia:

 public struct Acceleration { private readonly decimal rate; private readonly Vector vector; public Acceleration(decimal rate, Vector vector) { this.vector = vector; this.rate = rate; } public static Acceleration operator +(Acceleration other) { if (other.Vector.Z >= 0) { return other; } return new Acceleration(other.Rate, new Vector(other.vector.X, other.Vector.Y, -other.vector.Z)); } public static Acceleration operator -(Acceleration other) { if (other.Vector.Z <= 0) { return other; } return new Acceleration(other.Rate, new Vector(other.vector.X, other.Vector.Y, -other.vector.Z)); } public decimal Rate { get { return rate; } } public Vector Vector { get { return vector; } } }