Namespaces
Variants

Arithmetic operators

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

Retourne le résultat d'une opération arithmétique spécifique.

Nom de l'opérateur Syntaxe Exemples de prototypes (pour class T )
Définition à l'intérieur de la classe Définition à l'extérieur de la classe
Plus unaire + a T T :: operator + ( ) const ; T operator + ( const T & a ) ;
Moins unaire - a T T :: operator - ( ) const ; T operator - ( const T & a ) ;
Addition a + b T T :: operator + ( const T2 & b ) const ; T operator + ( const T & a, const T2 & b ) ;
Soustraction a - b T T :: operator - ( const T2 & b ) const ; T operator - ( const T & a, const T2 & b ) ;
Multiplication a * b T T :: operator * ( const T2 & b ) const ; T operator * ( const T & a, const T2 & b ) ;
Division a / b T T :: operator / ( const T2 & b ) const ; T operator / ( const T & a, const T2 & b ) ;
Reste a % b T T :: operator % ( const T2 & b ) const ; T operator % ( const T & a, const T2 & b ) ;
NOT binaire ~a T T :: operator ~ ( ) const ; T operator~ ( const T & a ) ;
ET bit à bit a & b T T :: operator & ( const T2 & b ) const ; T operator & ( const T & a, const T2 & b ) ;
OU au niveau des bits a | b T T :: operator | ( const T2 & b ) const ; T operator | ( const T & a, const T2 & b ) ;
OU exclusif au niveau des bits a ^ b T T :: operator ^ ( const T2 & b ) const ; T operator ^ ( const T & a, const T2 & b ) ;
Décalage à gauche au niveau du bit a << b T T :: operator << ( const T2 & b ) const ; T operator << ( const T & a, const T2 & b ) ;
Décalage à droite binaire a >> b T T :: operator >> ( const T2 & b ) const ; T operator >> ( const T & a, const T2 & b ) ;
Notes
  • Tous les opérateurs de ce tableau sont surchargeables .
  • Tous les opérateurs intégrés renvoient des valeurs, et la plupart des surcharges définies par l'utilisateur renvoient également des valeurs afin que les opérateurs définis par l'utilisateur puissent être utilisés de la même manière que les opérateurs intégrés. Cependant, dans une surcharge d'opérateur définie par l'utilisateur, n'importe quel type peut être utilisé comme type de retour (y compris void ). En particulier, les surcharges d'insertion de flux et d'extraction de flux de operator << et operator >> renvoient T& .
  • T2 peut être n'importe quel type, y compris T .

Table des matières

Explication générale

Tous les opérateurs arithmétiques intégrés calculent le résultat d'une opération arithmétique spécifique et retournent son résultat. Les arguments ne sont pas modifiés.

Conversions

Si l'opérande passé à un opérateur arithmétique intégré est de type intégral ou de type énumération non-scopée, alors avant toute autre action (mais après la conversion lvalue-vers-rvalue, si applicable), l'opérande subit la promotion intégrale . Si un opérande a un type tableau ou fonction, la conversion tableau-vers-pointeur et la conversion fonction-vers-pointeur sont appliquées.

Pour les opérateurs binaires (sauf les décalages), si les opérandes promus ont des types différents, les conversions arithmétiques usuelles sont appliquées.

Dépassements

L'arithmétique des entiers non signés est toujours effectuée modulo 2 n
où n est le nombre de bits dans cet entier particulier. Par exemple, pour unsigned int , ajouter un à UINT_MAX donne 0 , et soustraire un de 0 donne UINT_MAX .

Lorsqu'une opération arithmétique sur des entiers signés dépasse la capacité (le résultat ne tient pas dans le type de résultat), le comportement est indéfini — les manifestations possibles d'une telle opération incluent :

  • il boucle selon les règles de la représentation (généralement le complément à deux ),
  • il génère un piège — sur certaines plateformes ou via des options de compilation (par exemple -ftrapv dans GCC et Clang),
  • il sature à la valeur minimale ou maximale (sur de nombreux DSP),
  • il est complètement optimisé par le compilateur .

Environnement de virgule flottante

Si #pragma STDC FENV_ACCESS est pris en charge et défini sur ON , tous les opérateurs arithmétiques à virgule flottante respectent la direction d'arrondi actuelle et signalent les erreurs arithmétiques à virgule flottante comme spécifié dans math_errhandling , sauf s'ils font partie d'un initialiseur statique (auquel cas les exceptions à virgule flottante ne sont pas levées et le mode d'arrondi est vers le plus proche).

Contraction en virgule flottante

Sauf si #pragma STDC FP_CONTRACT est pris en charge et défini sur OFF , tous les calculs en virgule flottante peuvent être effectués comme si les résultats intermédiaires avaient une plage et une précision infinies, c'est-à-dire que les optimisations qui omettent les erreurs d'arrondi et les exceptions en virgule flottante sont autorisées. Par exemple, le C++ permet l'implémentation de ( x * y ) + z avec une seule instruction CPU de multiplication-addition fusionnée ou l'optimisation de a = x * x * x * x ; en tmp = x * x ; a = tmp * tmp .

Sans rapport avec la contraction, les résultats intermédiaires de l'arithmétique en virgule flottante peuvent avoir une plage et une précision différentes de celles indiquées par leur type, voir FLT_EVAL_METHOD .

Formellement, la norme C++ ne fournit aucune garantie sur la précision des opérations en virgule flottante.

Opérateurs arithmétiques unaires

Les expressions d'opérateurs arithmétiques unaires ont la forme

+ expression (1)
- expression (2)
1) Plus unaire (promotion).
2) Moins unaire (négation).

Les opérateurs unaires + et - ont une précédence plus élevée que tous les opérateurs arithmétiques binaires, donc l'expression ne peut pas contenir d'opérateurs arithmétiques binaires de premier niveau. Ces opérateurs s'associent de droite à gauche :

+a - b; // équivalent à (+a) - b, PAS à +(a - b)
-c + d; // équivalent à (-c) + d, PAS à -(c + d)
+-e; // équivalent à +(-e), l'opérateur unaire + est une opération nulle si « e » est un type natif
     // car toute promotion possible est effectuée lors de la négation

Opérateurs arithmétiques unaires intégrés

1) Pour l'opérateur unaire plus intégré, expression doit être une prvalue de type arithmétique, énumération non délimitée ou pointeur. Une promotion entière est effectuée sur expression si elle a un type entier ou énumération non délimitée. Le type du résultat est le type (éventuellement promu) de expression .
Le résultat de la promotion intégrée est la valeur de expression . L'opération unaire intégrée est un no-op si l'opérande est une prvalue d'un type intégral promu ou d'un type pointeur. Sinon, le type ou la catégorie de valeur de l'opérande est modifié par promotion intégrale ou conversion lvalue-vers-rvalue, tableau-vers-pointeur, fonction-vers-pointeur, ou conversion définie par l'utilisateur. Par exemple, char est converti en int , et une expression lambda non générique sans capture est convertie en pointeur de fonction (depuis C++11) dans les expressions de plus unaire.
2) Pour l'opérateur unaire moins intégré, expression doit être une prvalue de type arithmétique ou d'énumération non délimitée. Une promotion entière est effectuée sur expression . Le type du résultat est le type promu de expression .
Le résultat de la négation intégrée est la négative du expression promue. Pour un non signé a , la valeur de - a est 2 N
-a
, où N est le nombre de bits après promotion.
  • En d'autres termes, le résultat est le complément à deux de l'opérande (où l'opérande et le résultat sont considérés comme non signés).

Surcharges

Dans la résolution de surcharge pour les opérateurs définis par l'utilisateur , pour chaque type arithmétique promu sans qualificatif cv A et pour chaque type T , les signatures de fonctions suivantes participent à la résolution de surcharge :

A operator + ( A )
T * operator + ( T * )
A operator - ( A )
#include <iostream>
int main()
{
    char c = 0x6a;
    int n1 = 1;
    unsigned char n2 = 1;
    unsigned int n3 = 1;
    std::cout << "char: " << c << " int: " << +c << "\n"
                 "-1, where 1 is signed: " << -n1 << "\n"
                 "-1, where 1 is unsigned char: " << -n2 << "\n"
                 "-1, where 1 is unsigned int: " << -n3 << '\n';
    char a[3];
    std::cout << "size of array: " << sizeof a << "\n"
                 "size of pointer: " << sizeof +a << '\n';
}

Sortie possible :

char: j int: 106
-1, where 1 is signed: -1
-1, where 1 is unsigned char: -1
-1, where 1 is unsigned int: 4294967295
size of array: 3
size of pointer: 8

Opérateurs additifs

Les expressions d'opérateur additif ont la forme

lhs + rhs (1)
lhs - rhs (2)
1) Plus binaire (addition).
2) Moins binaire (soustraction).

Les opérateurs binaires + et - ont une précédence plus élevée que tous les autres opérateurs arithmétiques binaires, à l'exception de * , / et % . Ces opérateurs s'associent de gauche à droite :

a + b * c;  // équivalent à a + (b * c),  PAS (a + b) * c
d / e - f;  // équivalent à (d / e) - f,  PAS d / (e - f)
g + h >> i; // équivalent à (g + h) >> i, PAS g + (h >> i)
j - k + l - m; // équivalent à ((j - k) + l) - m

Opérateurs additifs intégrés

Pour les opérateurs binaires plus et moins intégrés, les deux lhs et rhs doivent être des prvalues, et l'une des conditions suivantes doit être satisfaite :

  • Les deux opérandes sont de type arithmétique ou énumération non délimitée. Dans ce cas, les conversions arithmétiques usuelles sont appliquées aux deux opérandes.
  • Exactement un opérande est de type entier ou énumération non délimitée. Dans ce cas, la promotion entière est appliquée à cet opérande.

Dans la description restante de cette section, « opérande(s) », lhs et rhs font référence aux opérande(s) converti(s) ou promu(s).

1) Pour l'addition intégrée, l'une des conditions suivantes doit être satisfaite :
  • Les deux opérandes ont un type arithmétique. Dans ce cas, le résultat est la somme des opérandes.
  • Un opérande est un pointeur vers un type d'objet complètement défini, et l'autre opérande a un type entier. Dans ce cas, la valeur entière est ajoutée au pointeur (voir pointer arithmetic ).
2) Pour la soustraction intégrée, l'une des conditions suivantes doit être satisfaite :
  • Les deux opérandes ont un type arithmétique. Dans ce cas, le résultat est la différence résultant de la soustraction de rhs à lhs .
  • lhs est un pointeur vers un type d'objet complètement défini, et rhs a un type entier. Dans ce cas, la valeur entière est soustraite du pointeur (voir arithmétique des pointeurs ).
  • Les deux opérandes sont des pointeurs vers des versions qualifiées cv ou non qualifiées cv du même type d'objet complètement défini. Dans ce cas rhs est soustrait de lhs (voir arithmétique des pointeurs ).

Si les deux opérandes ont un type à virgule flottante, et que le type prend en charge l'arithmétique à virgule flottante IEEE (voir std::numeric_limits::is_iec559 ):

  • Si un opérande est NaN, le résultat est NaN.
  • L'infini moins l'infini est NaN, et FE_INVALID est déclenché.
  • L'infini plus l'infini négatif est NaN, et FE_INVALID est déclenché.

Arithmétique des pointeurs

Lorsqu'une expression J de type intégral est ajoutée ou soustraite d'une expression P de type pointeur, le résultat a le type de P .

  • Si P évalue à une valeur de pointeur nul et J évalue à 0 , le résultat est une valeur de pointeur nul.
  • Sinon, si P pointe vers le i ème élément d'un objet tableau x avec n éléments, étant donné la valeur de J comme j , P est ajouté ou soustrait comme suit :
  • Les expressions P + J et J + P
  • pointent vers le i+j ème élément de x si i + j est dans [ 0 , n ) , et
  • sont des pointeurs après la fin du dernier élément de x si i + j est n .
  • L'expression P - J
  • pointe vers le i-j ème élément de x si i - j est dans [ 0 , n ) , et
  • est un pointeur après la fin du dernier élément de x si i - j est n .
  • Les autres valeurs de j entraînent un comportement indéfini.
  • Sinon, si P pointe vers un objet complet, un sous-objet de classe de base ou un sous-objet membre y , étant donné la valeur de J comme j , P est ajouté ou soustrait comme suit :
  • Les expressions P + J et J + P
  • pointent vers y si j est 0 , et
  • sont des pointeurs au-delà de la fin de y si j est 1 .
  • L'expression P - J
  • pointe vers y si j est 0 , et
  • est un pointeur au-delà de la fin de y si j est - 1 .
  • Les autres valeurs de j entraînent un comportement indéfini.
  • Sinon, si P est un pointeur au-delà de la fin d'un objet z , étant donné la valeur de J comme j :
  • Si z est un objet tableau avec n éléments, P est ajouté ou soustrait comme suit :
  • Les expressions P + J et J + P
  • pointent vers le n+j ième élément de z si n + j est dans [ 0 , n ) , et
  • sont des pointeurs après la fin du dernier élément de z si j est 0 .
  • L'expression P - J
  • pointe vers le n-j ième élément de z si n - j est dans [ 0 , n ) , et
  • est un pointeur après la fin du dernier élément de z si j est 0 .
  • Les autres valeurs de j entraînent un comportement indéfini.
  • Sinon, P est ajouté ou soustrait comme suit :
  • Les expressions P + J et J + P
  • pointent vers z si j est - 1 , et
  • sont des pointeurs après la fin de z si j est 0 .
  • L'expression P - J
  • pointe vers z si j est 1 , et
  • est un pointeur après la fin de z si j est 0 .
  • Les autres valeurs de j entraînent un comportement indéfini.
  • Sinon, le comportement n'est pas défini.

Lorsque deux expressions de pointeur P et Q sont soustraites, le type du résultat est std::ptrdiff_t .

  • Si P et Q évaluent tous deux à des valeurs de pointeur nul , le résultat est 0 .
  • Sinon, si P et Q pointent respectivement vers le i -ième et le j -ième élément du même tableau x , l'expression P - Q a pour valeur i − j .
  • Si i − j n'est pas représentable par std::ptrdiff_t , le comportement est indéfini.
  • Sinon, si P et Q pointent vers le même objet complet, sous-objet de classe de base ou sous-objet membre, le résultat est 0 .
  • Sinon, le comportement est indéfini.

Ces opérateurs arithmétiques de pointeur permettent aux pointeurs de satisfaire les LegacyRandomAccessIterator requirements.

Pour l'addition et la soustraction, si P ou Q ont le type « pointeur vers T (éventuellement qualifié cv) », où T et le type d'élément du tableau ne sont pas similaires , le comportement est indéfini :

int arr[5] = {1, 2, 3, 4, 5};
unsigned int *p = reinterpret_cast<unsigned int*>(arr + 1);
unsigned int k = *p; // OK, la valeur de « k » est 2
unsigned int *q = p + 1; // comportement indéfini : « p » pointe vers int, pas unsigned int

Surcharges

Dans la résolution de surcharge pour les opérateurs définis par l'utilisateur , pour chaque paire de types arithmétiques promus L et R et pour chaque type objet T , les signatures de fonctions suivantes participent à la résolution de surcharge :

LR opérateur + ( L, R )
LR opérateur - ( L, R )
T * opérateur + ( T * , std:: ptrdiff_t )
T * opérateur + ( std:: ptrdiff_t , T * )
T * opérateur - ( T * , std:: ptrdiff_t )
std:: ptrdiff_t opérateur - ( T * , T * )

LR est le résultat des conversions arithmétiques habituelles appliquées à L et R .

#include <iostream>
int main()
{
    char c = 2;
    unsigned int un = 2;
    int n = -10;
    std::cout << " 2 + (-10), where 2 is a char    = " << c + n << "\n"
                 " 2 + (-10), where 2 is unsigned  = " << un + n << "\n"
                 " -10 - 2.12  = " << n - 2.12 << '\n';
    char a[4] = {'a', 'b', 'c', 'd'};
    char* p = &a[1];
    std::cout << "Pointer addition examples: " << *p << *(p + 2)
              << *(2 + p) << *(p - 1) << '\n';
    char* p2 = &a[4];
    std::cout << "Pointer difference: " << p2 - p << '\n';
}

Sortie :

 2 + (-10), where 2 is a char    = -8
 2 + (-10), where 2 is unsigned  = 4294967288
 -10 - 2.12  = -12.12
Pointer addition examples: bdda
Pointer difference: 3

Opérateurs multiplicatifs

Les expressions d'opérateur multiplicatif ont la forme

lhs * rhs (1)
lhs / rhs (2)
lhs % rhs (3)
1) Multiplication.
2) Division.
3) Reste.

Les opérateurs multiplicatifs ont une précédence plus élevée que tous les autres opérateurs arithmétiques binaires. Ces opérateurs s'associent de gauche à droite :

a + b * c;  // équivalent à a + (b * c),  PAS (a + b) * c
d / e - f;  // équivalent à (d / e) - f,  PAS d / (e - f)
g % h >> i; // équivalent à (g % h) >> i, PAS g % (h >> i)
j * k / l % m; // équivalent à ((j * k) / l) % m

Opérateurs multiplicatifs intégrés

Pour les opérateurs de multiplication et de division intégrés, les deux opérandes doivent être de type arithmétique ou d'énumération non délimitée. Pour l'opérateur de reste intégré, les deux opérandes doivent être de type intégral ou d'énumération non délimitée. Conversions arithmétiques usuelles sont effectuées sur les deux opérandes.

Dans la description restante de cette section, « opérande(s) », lhs et rhs font référence aux opérande(s) converti(s).

1) Le résultat de la multiplication intégrée est le produit des opérandes.
Si les deux opérandes ont un type à virgule flottante, et que le type prend en charge l'arithmétique à virgule flottante IEEE (voir std::numeric_limits::is_iec559 ) :
  • La multiplication d'un NaN par n'importe quel nombre donne NaN.
  • La multiplication de l'infini par zéro donne NaN et FE_INVALID est déclenché.
2) Le résultat de la division intégrée est lhs divisé par rhs . Si rhs est zéro, le comportement est indéfini.
Si les deux opérandes ont un type intégral, le résultat est le quotient algébrique (effectue une division entière) : le quotient est tronqué vers zéro (la partie fractionnaire est écartée).
Si les deux opérandes ont un type à virgule flottante et que le type prend en charge l'arithmétique à virgule flottante IEEE (voir std::numeric_limits::is_iec559 ) :
  • Si un opérande est NaN, le résultat est NaN.
  • Diviser un nombre non nul par ±0.0 donne l'infini avec le signe correct et FE_DIVBYZERO est déclenché.
  • Diviser 0.0 par 0.0 donne NaN et FE_INVALID est déclenché.
3) Le résultat du reste intégré est le reste de la division entière de lhs par rhs . Si rhs est zéro, le comportement est indéfini.
Si a / b est représentable dans le type de résultat, ( a / b ) * b + a % b == a .
Si a / b n'est pas représentable dans le type de résultat, le comportement de a / b et de a % b est indéfini (ce qui signifie que INT_MIN % - 1 est indéfini sur les systèmes en complément à deux).

Note : Jusqu'à ce que CWG issue 614 soit résolue ( N2757 ), si un ou deux opérandes de l'opérateur binaire % étaient négatifs, le signe du reste était défini par l'implémentation, car il dépend de la direction d'arrondi de la division entière. La fonction std::div fournissait un comportement bien défini dans ce cas.

Remarque : pour le reste en virgule flottante, voir std::remainder et std::fmod .

Surcharges

Dans la résolution de surcharge pour les opérateurs définis par l'utilisateur , pour chaque paire de types arithmétiques promus LA et RA et pour chaque paire de types entiers promus LI et RI , les signatures de fonctions suivantes participent à la résolution de surcharge :

LRA operator * ( LA, RA )
LRA operator / ( LA, RA )
LRI operator % ( LI, RI )

LRx est le résultat des conversions arithmétiques usuelles appliquées à Lx et Rx .

#include <iostream>
int main()
{
    char c = 2;
    unsigned int un = 2;
    int  n = -10;
    std::cout << "2 * (-10), where 2 is a char    = " << c * n << "\n"
                 "2 * (-10), where 2 is unsigned  = " << un * n << "\n"
                 "-10 / 2.12  = " << n / 2.12 << "\n"
                 "-10 / 21  = " << n / 21 << "\n"
                 "-10 % 21  = " << n % 21 << '\n';
}

Sortie :

2 * (-10), where 2 is a char    = -20
2 * (-10), where 2 is unsigned  = 4294967276
-10 / 2.12  = -4.71698
-10 / 21  = 0
-10 % 21  = -10

Opérateurs logiques bit à bit

Les expressions d'opérateurs logiques bit à bit ont la forme

~ rhs (1)
lhs & rhs (2)
lhs | rhs (3)
lhs ^ rhs (4)
**Note:** Le contenu HTML fourni ne contient aucun texte traduisible en dehors des balises ` `. Les termes `lhs` et `rhs` sont des termes spécifiques au C++ (left-hand side/right-hand side) et ne doivent pas être traduits selon les instructions. Les numéros (1) à (4) sont des identifiants et restent inchangés. Aucune traduction n'était donc nécessaire dans ce cas précis.
1) Opérateur de complément bit à bit.
2) ET bit à bit.
3) OU au niveau des bits.
4) OU exclusif bit à bit.

L'opérateur de négation bit à bit a une précédence plus élevée que tous les opérateurs arithmétiques binaires. Il s'associe de droite à gauche :

~a - b; // équivalent à (~a) - b, PAS ~(a - b)
~c * d; // équivalent à (~c) * d, PAS ~(c * d)
~-e; // équivalent à ~(-e)

Il existe une ambiguïté dans la grammaire lorsque ~ est suivi d'un nom de type ou d'un spécificateur decltype (depuis C++11) : il peut s'agir soit de l'opérateur~, soit du début d'un identifiant de destructeur ). L'ambiguïté est résolue en traitant ~ comme opérateur~. ~ ne peut commencer un identifiant de destructeur qu'aux endroits où la formation d'un opérateur~ est syntaxiquement invalide.

Tous les autres opérateurs logiques bit à bit ont une précédence inférieure à tous les autres opérateurs arithmétiques binaires. Le ET bit à bit a une précédence supérieure au OU exclusif bit à bit, qui a une précédence supérieure au OU bit à bit. Ils s'associent de gauche à droite :

a & b * c;  // équivalent à a & (b * c),  PAS (a & b) * c
d / e ^ f;  // équivalent à (d / e) ^ f,  PAS d / (e ^ f)
g << h | i; // équivalent à (g << h) | i, PAS g << (h | i)
j & k & l; // équivalent à (j & k) & l
m | n ^ o  // équivalent à m | (n ^ o)

Opérateurs logiques bit à bit intégrés

Pour l'opérateur de négation bit à bit intégré, rhs doit être une prvalue de type entier ou énumération non délimitée, et une promotion entière est effectuée sur rhs . Pour les autres opérateurs logiques bit à bit intégrés, les deux opérandes doivent avoir un type entier ou énumération non délimitée, et les conversions arithmétiques usuelles sont effectuées sur les deux opérandes.

Dans la description restante de cette section, « opérande(s) », lhs et rhs font référence aux opérande(s) converti(s) ou promu(s).

1) Soit l'opérande x et le résultat de l'opération NOT bit à bit intégrée r . Pour chaque coefficient x_i de la représentation en base 2 de x , le coefficient correspondant r_i de la représentation en base 2 de r est 1 si x_i est 0 , et 0 sinon.
  • Autrement dit, le résultat est le complément à un de l'opérande (où l'opérande et le résultat sont considérés comme non signés).
Le type du résultat r est le type de l'opérande x .
2-4) Étant donné les opérandes x et y respectivement et le résultat des opérations logiques binaires intégrées comme r . Pour chaque paire de coefficients x_i et y_i des représentations en base 2 de x et y respectivement, le coefficient correspondant r_i de la représentation en base 2 de r est
2) 1 si les deux x_i et y_i sont 1 , et 0 sinon.
3) 1 si au moins l'un des x_i et y_i est 1 , et 0 sinon.
4) 1 si l'un (mais pas les deux) des x_i et y_i vaut 1 , et 0 sinon.
Le type du résultat r est le type des opérandes x et y .

Surcharges

Dans la résolution de surcharge pour les opérateurs définis par l'utilisateur , pour chaque paire de types entiers promus L et R , les signatures de fonctions suivantes participent à la résolution de surcharge :

R operator~ ( R )
LR operator & ( L, R )
LR operator ^ ( L, R )
LR operator | ( L, R )

LR est le résultat des conversions arithmétiques usuelles appliquées à L et R .

#include <bitset>
#include <cstdint>
#include <iomanip>
#include <iostream>
int main()
{
    std::uint16_t mask = 0x00f0;
    std::uint32_t x0 = 0x12345678;
    std::uint32_t x1 = x0 | mask;
    std::uint32_t x2 = x0 & ~mask;
    std::uint32_t x3 = x0 & mask;
    std::uint32_t x4 = x0 ^ mask;
    std::uint32_t x5 = ~x0;
    using bin16 = std::bitset<16>;
    using bin32 = std::bitset<32>;
    std::cout << std::hex << std::showbase
              << "Masque : " << mask << std::setw(49) << bin16(mask) << "\n"
                 "Valeur : " << x0 << std::setw(42) << bin32(x0) << "\n"
                 "Définition des bits : " << x1 << std::setw(35) << bin32(x1) << "\n"
                 "Effacement des bits : " << x2 << std::setw(34) << bin32(x2) << "\n"
                 "Sélection des bits : " << x3 << std::setw(39) << bin32(x3) << "\n"
                 "Bits XOR : " << x4 << std::setw(35) << bin32(x4) << "\n"
                 "Inversion des bits : " << x5 << std::setw(33) << bin32(x5) << '\n';
}

Sortie :

Masque : 0xf0                                 0000000011110000
Valeur : 0x12345678          00010010001101000101011001111000
Définition des bits : 0x123456f8   00010010001101000101011011111000
Effacement des bits : 0x12345608  00010010001101000101011000001000
Sélection des bits : 0x70       00000000000000000000000001110000
Bits XOR : 0x12345688   00010010001101000101011010001000
Inversion des bits : 0xedcba987 11101101110010111010100110000111

Opérateurs de décalage binaire

Les expressions d'opérateur de décalage bit à bit ont la forme

lhs << rhs (1)
lhs >> rhs (2)
1) Décalage binaire vers la gauche.
2) Décalage vers la droite au niveau des bits.

Les opérateurs de décalage bit à bit ont une précédence plus élevée que les opérateurs logiques bit à bit, mais une précédence inférieure à celle des opérateurs additifs et multiplicatifs. Ces opérateurs s'associent de gauche à droite :

a >> b * c;  // équivalent à a >> (b * c),  PAS (a >> b) * c
d << e & f;  // équivalent à (d << e) & f,  PAS d << (e & f)
g << h >> i; // équivalent à (g << h) >> i, PAS g << (h >> i)

Opérateurs de décalage binaire intégrés

Pour les opérateurs de décalage binaire intégrés, les deux opérandes doivent être des prvalues de type entier ou d'énumération non délimitée. Des promotions entières sont effectuées sur les deux opérandes.

Dans la description restante de cette section, « opérande(s) », a , b , lhs et rhs font référence aux opérande(s) converti(s) ou promu(s).

Si la valeur de rhs est négative ou n'est pas inférieure au nombre de bits dans lhs , le comportement est indéfini.

Pour un type non signé a , la valeur de a << b est la valeur de a * 2 b
, réduite modulo 2 N
où N est le nombre de bits dans le type de retour (c'est-à-dire qu'un décalage vers la gauche au niveau des bits est effectué et les bits qui sont décalés hors du type de destination sont perdus).

Pour un type signé et non négatif a , si a * 2 b
est représentable dans la version non signée du type de retour, alors cette valeur, convertie en signé, est la valeur de a << b (ce qui rend légal de créer INT_MIN comme 1 << 31 ) ; sinon le comportement est indéfini.

Pour un a négatif, le comportement de a << b est indéfini.

Pour un type non signé a et pour un type signé et non négatif a , la valeur de a >> b est la partie entière de a/2 b
.

Pour un a négatif, la valeur de a >> b est définie par l'implémentation (dans la plupart des implémentations, cela effectue un décalage arithmétique vers la droite, de sorte que le résultat reste négatif).

(jusqu'à C++20)

La valeur de a << b est la valeur unique congrue à a * 2 b
modulo 2 N
où N est le nombre de bits dans le type de retour (c'est-à-dire qu'un décalage vers la gauche au niveau des bits est effectué et les bits qui sont décalés hors du type de destination sont perdus).

La valeur de a >> b est a/2 b
, arrondie vers l'infini négatif (en d'autres termes, le décalage vers la droite sur un a signé est un décalage arithmétique vers la droite).

(depuis C++20)

Le type du résultat est celui de lhs .

Surcharges

Dans la résolution de surcharge pour les opérateurs définis par l'utilisateur , pour chaque paire de types entiers promus L et R , les signatures de fonctions suivantes participent à la résolution de surcharge :

L operator << ( L, R )
L operator >> ( L, R )
#include <iostream>
enum { ONE = 1, TWO = 2 };
int main()
{
    std::cout << std::hex << std::showbase;
    char c = 0x10;
    unsigned long long ull = 0x123;
    std::cout << "0x123 << 1 = " << (ull << 1) << "\n"
                 "0x123 << 63 = " << (ull << 63) << "\n" // dépassement en non signé
                 "0x10 << 10 = " << (c << 10) << '\n';   // char est promu en int
    long long ll = -1000;
    std::cout << std::dec << "-1000 >> 1 = " << (ll >> ONE) << '\n';
}

Sortie :

0x123 << 1 = 0x246
0x123 << 63 = 0x8000000000000000
0x10 << 10 = 0x4000
-1000 >> 1 = -500

Bibliothèque standard

Les opérateurs arithmétiques sont surchargés pour de nombreux types de la bibliothèque standard.

Opérateurs arithmétiques unaires

implémente les opérateurs unaires + et -
(fonction membre publique de std::chrono::duration<Rep,Period> )
applique les opérateurs unaires aux nombres complexes
(fonction template)
applique un opérateur arithmétique unaire à chaque élément du valarray
(fonction membre publique de std::valarray<T> )

Opérateurs additifs

effectue des opérations d'addition et de soustraction impliquant un point temporel
(modèle de fonction)
implémente des opérations arithmétiques avec des durées comme arguments
(modèle de fonction)
ajoute ou soustrait un year_month_day et un certain nombre d'années ou de mois
(fonction)
concatène deux chaînes, une chaîne et un char , ou une chaîne et une string_view
(modèle de fonction)
avance ou décrémente l'itérateur
(fonction membre publique de std::reverse_iterator<Iter> )
avance ou décrémente l'itérateur
(fonction membre publique de std::move_iterator<Iter> )
effectue des opérations arithmétiques sur deux nombres complexes ou un complexe et un scalaire
(modèle de fonction)
applique des opérateurs binaires à chaque élément de deux valarrays, ou un valarray et une valeur
(modèle de fonction)

Opérateurs multiplicatifs

implémente les opérations arithmétiques avec des durées comme arguments
(modèle de fonction)
effectue des opérations arithmétiques sur des nombres complexes entre deux valeurs complexes ou entre un complexe et un scalaire
(modèle de fonction)
applique des opérateurs binaires à chaque élément de deux valarrays, ou d'un valarray et d'une valeur
(modèle de fonction)

Opérateurs logiques bit à bit

effectue les opérations binaires ET, OU, XOR et NON
(fonction membre publique de std::bitset<N> )
effectue des opérations logiques binaires sur les bitsets
(fonction template)
applique un opérateur arithmétique unaire à chaque élément du valarray
(fonction membre publique de std::valarray<T> )
applique des opérateurs binaires à chaque élément de deux valarrays, ou d'un valarray et d'une valeur
(fonction template)

Opérateurs de décalage binaire

applique des opérateurs binaires à chaque élément de deux valarrays, ou d'un valarray et d'une valeur
(modèle de fonction)
effectue un décalage binaire vers la gauche et vers la droite
(fonction membre publique de std::bitset<N> )

Opérateurs d'insertion/extraction de flux

Dans la bibliothèque standard, les opérateurs de décalage bit à bit sont couramment surchargés avec les flux d'E/S ( std:: ios_base & ou l'une des classes qui en dérivent) comme opérande gauche et type de retour. Ces opérateurs sont connus sous le nom d' opérateurs d'insertion de flux et d' opérateurs d'extraction de flux :

extrait des données formatées
(fonction membre publique de std::basic_istream<CharT,Traits> )
extrait des caractères et tableaux de caractères
(modèle de fonction)
insère des données formatées
(fonction membre publique de std::basic_ostream<CharT,Traits> )
insère des données caractère ou insertion dans un flux rvalue
(modèle de fonction)
sérialise et désérialise un nombre complexe
(modèle de fonction)
effectue l'entrée/sortie de flux sur les bitsets
(modèle de fonction)
effectue l'entrée/sortie de flux sur les chaînes
(modèle de fonction)
effectue l'entrée/sortie de flux sur un moteur de nombres pseudo-aléatoires
(modèle de fonction)
effectue l'entrée/sortie de flux sur une distribution de nombres pseudo-aléatoires
(modèle de fonction)

Rapports de défauts

Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.

DR Appliqué à Comportement tel que publié Comportement correct
CWG 614 C++98 le quotient algébrique de la division entière était
arrondi dans une direction définie par l'implémentation
le quotient algébrique de la division
entière est tronqué vers zéro
(la partie fractionnaire est ignorée)
CWG 1450 C++98 le résultat de a / b était non spécifié si
il n'est pas représentable dans le type de résultat
le comportement de a / b et
a % b est indéfini dans ce cas
CWG 1457 C++98 le comportement du décalage du bit 1 le plus à gauche d'une
valeur signée positive dans le bit de signe était indéfini
rendu bien défini
CWG 1504 C++98 un pointeur vers un sous-objet de classe de base d'un élément
de tableau pouvait être utilisé dans l'arithmétique des pointeurs
le comportement est
indéfini dans ce cas
CWG 1515 C++98 seuls les entiers non signés déclarés unsigned
devaient obéir aux lois de l'arithmétique modulo 2 n
s'applique à tous les entiers non signés
CWG 1642 C++98 les opérateurs arithmétiques autorisaient leurs opérandes à être des lvalues certains opérandes doivent être des rvalues
CWG 1865 C++98 la résolution de CWG issue 1504 rendait les comportements
de l'arithmétique des pointeurs impliquant des pointeurs vers des éléments de tableau
indéfinis si le type pointé et le type de l'élément du tableau
ont des qualifications cv différentes dans les niveaux non supérieurs
rendu bien défini
CWG 1971 C++98 il n'était pas clair si la règle résolvant l'
ambiguïté de ~ s'appliquait à des cas tels que ~X ( 0 )
la règle s'applique à de tels cas
CWG 2419 C++98 un pointeur vers un objet non-tableau n'était traité comme un
pointeur vers le premier élément d'un tableau de taille 1
dans l'arithmétique des pointeurs que si le pointeur est obtenu par &
s'applique à tous les pointeurs
vers des objets non-tableau
CWG 2626 C++98 le résultat de l'opérateur intégré operator~ était simplement
'complément à un' sans définition appropriée
le résultat est formulé en termes
de représentation en base 2
CWG 2724 C++20 la direction d'arrondi du décalage arithmétique à droite n'était pas claire clarifiée
CWG 2853 C++98 un pointeur au-delà de la fin d'un objet ne pouvait
pas être ajouté ou soustrait avec un entier
il peut l'être

Voir aussi

Priorité des opérateurs

Surcharge d'opérateur

Opérateurs courants
affectation incrémentation
décrémentation
arithmétique logique comparaison accès
membre
autre

a = b
a + = b
a - = b
a * = b
a / = b
a % = b
a & = b
a | = b
a ^ = b
a <<= b
a >>= b

++ a
-- a
a ++
a --

+ a
- a
a + b
a - b
a * b
a / b
a % b
~a
a & b
a | b
a ^ b
a << b
a >> b

! a
a && b
a || b

a == b
a ! = b
a < b
a > b
a <= b
a >= b
a <=> b

a [ ... ]
* a
& a
a - > b
a. b
a - > * b
a. * b

appel de fonction

a ( ... )
virgule

a, b
conditionnel

a ? b : c
Opérateurs spéciaux

static_cast convertit un type en un autre type apparenté
dynamic_cast convertit au sein des hiérarchies d'héritage
const_cast ajoute ou supprime les qualificateurs cv
reinterpret_cast convertit un type en un type non apparenté
C-style cast convertit un type en un autre par un mélange de static_cast , const_cast , et reinterpret_cast
new crée des objets avec une durée de stockage dynamique
delete détruit les objets précédemment créés par l'expression new et libère la zone mémoire obtenue
sizeof interroge la taille d'un type
sizeof... interroge la taille d'un pack (depuis C++11)
typeid interroge les informations de type d'un type
noexcept vérifie si une expression peut lever une exception (depuis C++11)
alignof interroge les exigences d'alignement d'un type (depuis C++11)

Documentation C pour Opérateurs arithmétiques