Que fait l’opérateur unaire plus?

Que fait l’opérateur unaire plus? Il y a plusieurs définitions que j’ai trouvées ( ici et ici ) mais je n’ai toujours aucune idée de ce à quoi cela servirait. Il semble que cela ne fasse rien mais il y a une raison à cela, non?

C’est là pour être surchargé si vous en ressentez le besoin; pour tous les types prédéfinis, il s’agit essentiellement d’un no-op.

Les utilisations pratiques d’un opérateur arithmétique non unaire sont assez limitées et ont tendance à se rapporter aux conséquences de l’utilisation d’une valeur dans une expression arithmétique, plutôt que de l’opérateur lui-même. Par exemple, il peut être utilisé pour forcer l’élargissement de types entiers plus petits à int ou garantir que le résultat d’une expression est traité comme une valeur et n’est donc pas compatible avec un paramètre de référence non const . Je soutiens cependant que ces utilisations sont mieux adaptées au code golf que la lisibilité. 🙂

En fait, unaire plus fait quelque chose – même en C. Elle effectue les conversions arithmétiques habituelles sur l’opérande et renvoie une nouvelle valeur, qui peut être un entier de plus grande largeur. Si la valeur d’origine était un entier non signé de largeur inférieure à int , elle deviendrait également une valeur signed .

Habituellement, ce n’est pas si important, mais cela peut avoir un effet, donc ce n’est pas une bonne idée d’utiliser un plus unaire comme une sorte de “commentaire” indiquant qu’un entier est positif. Considérez le programme C ++ suivant:

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

Cela affichera "x est un int".

Ainsi, dans cet exemple, unaire plus a créé une nouvelle valeur avec un type et une signature différents.

Je l’ai vu utilisé pour plus de clarté, pour souligner la valeur positive par opposition à une valeur négative:

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

Mais c’est une utilisation assez faible. La réponse est définitivement surchargée.

De la deuxième édition de K & R:

L’Unaire + est nouveau avec la norme ANSI. Il a été ajouté pour la symésortinge avec l’unaire -.

Une chose que fait unary + intégré fait de la lvalue une valeur. Par exemple, vous pouvez le faire

 int x; &x; 

mais tu ne peux pas faire ça

 &+x; 

🙂

PS “La surcharge” n’est certainement pas la bonne réponse. Unary + été hérité de C et il n’y a pas d’opérateur de niveau utilisateur en surcharge en C.

La principale chose accomplie par unary + est la promotion de type dans un int pour les types de données plus petits que int. Cela peut être très utile si vous essayez d’imprimer des données de caractères en utilisant std::cout comme données numériques.

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

est très différent de

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

Il est également disponible pour la surcharge, mais en pratique, votre surcharge devrait être presque un NOP.

Si vous avez besoin d’imprimer la valeur numérique des octets bruts (par exemple, les petits nombres stockés en tant que caractères) pour le débogage ou pour une raison quelconque, unary + peut simplifier le code d’impression. Considérer

 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 

Ceci est juste un exemple rapide. Je suis sûr qu'il y a d'autres moments où unary + peut aider à traiter vos octets comme des nombres plutôt que comme du texte.

Pas tant. L’argument général pour autoriser la surcharge d’ operator+() est qu’il y a certainement des utilisations réelles pour surcharger operator-() , et ce serait très étrange (ou asymésortingque) si vous autorisiez une surcharge d’ operator-() mais pas d’ operator+() .

Je crois que j’ai d’abord lu cet argument de Stroustrop, mais je n’ai pas mes livres avec moi pour le vérifier. J’ai peut être tort.

Unary plus était présent dans C, où il ne faisait absolument rien (un peu comme le mot auto clé auto ). Pour ne pas l’avoir, Stroustrup aurait dû introduire une incompatibilité gratuite avec C.

Une fois qu’il était en C ++, il était naturel d’autoriser une fonction de surcharge, tout comme unary minus, et Stroustrup aurait pu l’introduire pour cette raison s’il n’y était pas déjà.

Donc, ça ne veut rien dire. Il peut être utilisé comme une sorte de décoration pour rendre les choses plus symésortingques, en utilisant +1,5 comme l’inverse de -1,5 par exemple. En C ++, il peut être surchargé, mais cela va être déroutant si operator+() fait quelque chose. Rappelez-vous la règle standard: en surchargeant les opérateurs arithmétiques, faites des choses comme les int s.

Si vous cherchez une raison pour laquelle il existe, trouvez quelque chose au sujet des premiers antécédents de C. Je pense qu’il n’y avait pas de bonne raison, car C n’était pas vraiment conçu. Considérons le mot auto clé auto inutile (probablement contrairement au mot auto clé static , qui est maintenant recyclé en C ++ 0x), et le mot-clé entry , qui n’a jamais rien fait (et plus tard omis dans C90). Il y a un email célèbre dans lequel Ritchie ou Kernighan disent que quand ils ont réalisé que la priorité de l’opérateur avait des problèmes, il y avait déjà trois installations avec des milliers de lignes de code qu’ils ne voulaient pas casser.

Une friandise historique. Le comité de normalisation de C99 a également estimé que les utilisations existantes de l’unaire plus étaient assez rares, comme en témoigne leur considération de les réutiliser pour obtenir une autre caractéristique du langage: inhibition de l’évaluation du temps de traduction des expressions constantes à virgule flottante. Voir la citation suivante de la justification C, section F.7.4:

Une version antérieure de cette spécification autorisait l’arithmétique constante du temps de traduction, mais permettait à l’opérateur unaire +, lorsqu’il était appliqué à un opérande, d’inhiber l’évaluation du temps de traduction des expressions constantes.

En fin de compte, la sémantique a été inversée, avec une évaluation de l’exécution exécutée dans la plupart des contextes (au moins jusqu’à la règle “comme si”), et la possibilité de procéder à une évaluation des temps de traduction en utilisant des initialiseurs statiques. Notez que la principale différence réside dans l’occurrence d’exceptions en virgule flottante et d’autres parameters d’arrondi ou de précision en virgule flottante, le cas échéant.

Je ne peux citer aucune source pour cela, mais j’ai fini par comprendre que c’est pour la promotion de type explicite, qui implique une conversion de type sans perte. Cela le place au sumt de la hiérarchie de conversion,

  • Promotion: new_type operator+(old_type)
  • Conversion: new_type(old_type)
  • Cast: operator(new_type)(old_type)
  • Coercition: new_type operator=(old_type)

Bien sûr, cela découle de mon interprétation d’une note dans l’un des manuels c / c ++ de microsoft (vraiment vieux) que j’ai lus il y a une quinzaine d’années, alors prenez-la avec un grain de sel.

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

Comme le montre l’exemple ci-dessus, l’unaire + change réellement le type, taille 4 et 2 respectivement. Bizarre que l’expression + x soit bien calculée dans la tailleof, j’ai pensé que ce n’était pas censé le faire. Peut-être est-ce dû au fait que sizeof a la même priorité que l’unary +.

Je suppose que vous pouvez l’utiliser pour rendre un nombre toujours positif. Il suffit de surcharger l’opérateur unaire + pour être abs. Cela ne vaut pas vraiment la peine de confondre vos collègues développeurs, à moins que vous souhaitiez simplement masquer votre code. Ensuite, ça fonctionnerait bien.

EDIT Réécrire complètement, parce que j’étais waaaayyy dans ma réponse originale.

Cela devrait vous permettre de gérer la déclaration explicite de votre type en tant que valeur positive (je pense que dans la plupart des opérations non mathématiques). Il semble que la négation serait plus utile, mais je suppose que voici un exemple où cela pourrait faire une différence:

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