Cosa fa l’operatore unario plus?

Cosa fa l’operatore unario plus? Ci sono diverse definizioni che ho trovato ( qui e qui ) ma non ho ancora idea di cosa sarebbe stato usato. Sembra che non faccia nulla, ma c’è una ragione per questo, giusto?

È lì per essere sovraccarico se ne senti il ​​bisogno; per tutti i tipi predefiniti è essenzialmente un no-op.

Gli usi pratici di un operatore aritmetico unario no-op sono piuttosto limitati e tendono a riguardare le conseguenze dell’uso di un valore in un’espressione aritmetica, piuttosto che l’operatore stesso. Ad esempio, può essere usato per forzare l’allargamento da tipi interi minori a int , o assicurare che il risultato di un’espressione sia trattato come un valore rval e quindi non compatibile con un parametro di riferimento non const . Io sostengo, tuttavia, che questi usi sono più adatti al codice del golf che alla leggibilità. 🙂

In realtà, unario plus fa qualcosa – anche in C. Esegue le consuete conversioni aritmetiche sull’operando e restituisce un nuovo valore, che può essere un numero intero di larghezza maggiore. Se il valore originale era un numero intero senza segno di larghezza minore di int , verrà modificato anche con un valore con segno.

Di solito questo non è così importante, ma può avere un effetto, quindi non è una buona idea usare unario come una sorta di “commento” che denota che un intero è positivo. Considera il seguente programma 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); } 

Questo mostrerà "x è un int".

Quindi in questo esempio unary plus ha creato un nuovo valore con un diverso tipo e firma.

L’ho visto usato per chiarezza, per enfatizzare il valore positivo come distinto da un valore negativo:

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

Ma questo è un uso piuttosto debole. La risposta è decisamente sovraccarico.

Dalla seconda edizione di K & R:

+ Unario è nuovo con lo standard ANSI. E ‘stato aggiunto per simmetria con l’unario -.

Una cosa che unario + built fa sta trasformando lvalue in un valore. Ad esempio, puoi farlo

 int x; &x; 

ma non puoi farlo

 &+x; 

🙂

PS “Sovraccarico” non è sicuramente la risposta giusta. Unary + stato ereditato da C e non vi è alcun overload di operatore a livello utente in C.

La cosa principale + unaria + è la promozione del tipo in un int per i tipi di dati più piccoli di int. Questo può essere molto utile se stai provando a stampare i dati del char usando std::cout come dati numerici.

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

è molto diverso da

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

È anche disponibile per sovraccaricare, ma in pratica il sovraccarico dovrebbe essere quasi un NOP.

Se è necessario stampare il valore numerico dei byte non elaborati (ad esempio, i piccoli numeri memorizzati come char) per il debug o qualsiasi altro motivo, unary + può semplificare il codice di stampa. Prendere in considerazione

 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 

Questo è solo un rapido esempio. Sono sicuro che ci sono altre volte in cui unary + può aiutare a trattare i tuoi byte più come numeri invece che come testo.

Non tanto. L’argomento generale per consentire il sovraccarico operator+() è che ci sono degli usi del mondo reale per l’overloading operator-() , e sarebbe molto strano (o asimmetrico) se si consentisse l’overloading operator-() ma non operator+() .

Credo di aver letto per la prima volta questo argomento da Stroustrop, ma non ho i miei libri con me giusto per verificarlo. Potrei sbagliarmi.

Unary plus era presente in C, dove non faceva assolutamente nulla (molto simile alla parola chiave auto ). Per non averlo, Stroustrup avrebbe dovuto introdurre un’incompatibilità gratuita con C.

Una volta in C ++, era naturale consentire una funzione di sovraccarico, proprio come un unus meno, e Stroustrup avrebbe potuto introdurlo per quel motivo se non fosse già lì.

Quindi, non significa niente. Può essere usato come una sorta di decorazione per rendere le cose più simmetriche, usando +1,5 come opposto a -1,5 per esempio. In C ++, può essere sovraccaricato, ma sarà confuso se l’ operator+() fa qualcosa. Ricorda la regola standard: quando sovraccarichi operatori aritmetici, fai cose come le int s do.

Se stai cercando una ragione per cui è lì, trova qualcosa sulla storia iniziale di C. Sospetto che non ci fosse una buona ragione, dato che C non era davvero progettato. Considera l’inutile parola chiave auto (presumibilmente in contrasto con la static , che ora viene riciclata in C ++ 0x), e la parola chiave entry , che non ha mai fatto nulla (e successivamente omessa in C90). C’è una famosa e-mail in cui Ritchie o Kernighan dicono che, quando hanno capito che la precedenza degli operatori aveva problemi, c’erano già tre installazioni con migliaia di righe di codice che non volevano interrompere.

Una boccata storica. Il comitato di standardizzazione C99 ha anche pensato che gli usi esistenti di unario plus fossero piuttosto rari, come dimostra il loro tentativo di riutilizzarlo per ottenere un’altra caratteristica del linguaggio: l’inibizione della valutazione del tempo di traduzione delle espressioni costanti in virgola mobile. Vedere la seguente citazione dal punto C, sezione F.7.4:

Una prima versione di questa specifica consentiva l’aritmetica costante della velocità di traduzione, ma abilitava l’operatore unario +, quando applicato a un operando, per inibire la valutazione del tempo di traduzione delle espressioni costanti.

Alla fine, la semantica è stata invertita, con la valutazione del tempo di esecuzione applicata nella maggior parte dei contesti (almeno fino alla regola “come se”) e la capacità di imporre la valutazione del tempo di traduzione mediante l’uso di inizializzatori statici. Si noti che la differenza principale risiede nell’occorrenza delle eccezioni in virgola mobile e in altri arrotondamenti in virgola mobile o nelle impostazioni di precisione, ove presenti.

Non posso citare alcuna fonte per questo, ma ho capito che è per la promozione del tipo esplicito, che implica la conversione del tipo senza perdita di dati. Questo lo mette in cima alla gerarchia di conversione,

  • Promozione: new_type operator+(old_type)
  • Conversione: new_type(old_type)
  • Cast: operator(new_type)(old_type)
  • Coercizione: new_type operator=(old_type)

Naturalmente, questo è dovuto alla mia interpretazione di una nota in uno dei manuali di microsoft (molto vecchi) c / c ++ che ho letto circa 15 anni fa, quindi prendila con un pizzico di sale.

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

Come mostrato nell’esempio sopra, l’unario + cambia davvero il tipo, dimensione 4 e 2 rispettivamente. Strano che l’espressione + x sia effettivamente calcasting in sizeof, pensavo che non fosse previsto. Forse è dovuto al fatto che sizeof ha la stessa priorità di unario +.

Suppongo che potresti usarlo per rendere sempre un numero positivo. Basta sovraccaricare l’operatore unario + per fare gli addominali. Non vale davvero la pena di confondere i tuoi colleghi sviluppatori, a meno che tu non voglia veramente solo offuscare il tuo codice. Quindi funzionerebbe bene.

EDIT Riscrivi completamente, perché stavo svegliandosi nella mia risposta originale.

Questo dovrebbe consentire di gestire la dichiarazione esplicita del tuo tipo come un valore positivo (penso in operazioni per lo più non matematiche). Sembra che la negazione sarebbe più utile, ma immagino che qui ci sia un esempio di dove potrebbe fare la differenza:

 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; } } }