Operatory arytmetyczne

Język C++

.

.

Zagadnienia ogólne
Kontrola przepływu
Warunkowe instrukcje wykonania

if

Instrukcje iteracyjne (pętle)

for

zakres-. return

Funkcje
Deklaracja funkcji
Deklaracja funkcji lambda
inline specyfikator
Specyfikatory wyjątków (do C++20)
. noexcept specifier (C++11)
Exceptions
Namespaces
Typy
Specyfikatory

decltype (C++11)

auto (C++11)

alignas (C++11)

. const/volatile

constexpr (C++11)

Specyfikatory czasu przechowywania
. Inicjalizacja
.

.

Wyrażenia
Reprezentacje alternatywne
Literały
Boolean – ang. Integer – Floating-point
Character – String – nullptr (C++11)
User-zdefiniowane (C++11)
Utilities
Atrybuty (C++11)
Typy
. typedef deklaracja
Deklaracja aliasu typu (C++11)
Rzutowanie
Konwersje niejawne -. Konwersje jawne
static_castdynamic_cast
const_cast -. reinterpret_cast
Alokacja pamięci
Klasy
Klasy-.specyficzne właściwości funkcji

Funkcja wirtualna

specyfikator override (C++11)

specyfikator final (C++11)

. explicit (C++11)

static

Specjalne funkcje członkowskie

Przypisanie kopiowania

Przypisanie przenoszenia (C++11)

Destruktor

Szablony

Specjalizacja szablonów

Pakiety parametrów (C++11)

Różne
Wyrażenia

Ogólne

kategorie wartości (lvalue, rvalue, xvalue)

kolejność oceny (punkty sekwencji)

wyrażenia stałe

wyrażenia niedokonujące oceny

wyrażenia pierwotne

wyrażenia lambda(C++11)

wyrażenia literalne

wyrażenia całkowite

wyrażenia zmiennoprzecinkowepunktowe

literały boolean

literały znaków, w tym sekwencje ucieczki

literały łańcuchów

literał wskaźnika null(C++11)

literał zdefiniowany przez użytkownika(C++11)

Operatory

Operatory przypisania: a=b, a+=b, a-=b, a*=b, a/=b, a%=b, a&=b, a|=b, a^=b, a<<=b, a>>=b

Inkrementacja i dekrementacja: ++a, --a, a++, a--

Operatory arytmetyczne:+a, -a, a+b, a-b, a*b, a/b, a%b, ~a, a&b, a|b, a^b, a<<b, a>>b

Operatory logiczne: a||b, a&&b, !a

Operatory porównania: a==b, a!=b, a<b, a>b, a<=b, a>=b, a<=>b(C++20)

Operatory dostępu do członów: a, *a, &a, a->b, a.b, a->*b, a.*b

Inne operatory: a(...), a,b, a?b:c

new-expression

delete-expression

throw-expression

alignof

sizeof

sizeof….(C++11)

typeid

noexcept(C++11)

Wyrażenie składane(C++17)

Alternatywne reprezentacje operatorów

Precedencja i asocjatywność

Przeciążanie operatorów

. Domyślne porównania(C++20)

Konwersje

Konwersje niejawne

const_cast

static_cast

reinterpret_cast

dynamic_cast

Konwersje jawne (T)a, T(a)

konwersja zdefiniowana przez użytkownika

Zwraca wynik określonej operacji arytmetycznej.

.

Nazwa operatora Składnia Przeciążalny Przykłady prototypów (dla klasy T)
Wewnątrz definicji klasy Na zewnątrz definicji klasy
unary plus +a Tak T T::operator+() const; T operator+(const T &a);
unary minus -a Yes T T.::operator-() const; T operator-(const T &a);
dodawanie a + b Tak T T::operator+(const T2 &b) const; T operator+(const T &a, const T2 &b);
odejmowanie a - b Tak T T::operator-(const T2 &b) const; T operator-(const T &a, const T2 &b);
mnożenie a * b Tak T T.::operator*(const T2 &b) const; T operator*(const T &a, const T2 &b);
dzielenie a / b Tak T T.::operator/(const T2 &b) const; T operator/(const T &a, const T2 &b);
modulo a % b Tak T T::operator%(const T2 &b) const; T operator%(const T &a, const T2 &b);
bitwise NOT ~a Yes T T.::operator~() const; T operator~(const T &a);
bitwise AND a & b Yes T T::operator&(const T2 &b) const; T operator&(const T &a, const T2 &b);
bitwise OR a | b Tak T T.::operator|(const T2 &b) const; T operator|(const T &a, const T2 &b);
bitwise XOR a ^ b Yes T T::operator^(const T2 &b) const; T operator^(const T &a, const T2 &b);
bitowe przesunięcie w lewo a << b Tak T T::operator<<(const T2 &b) const; T operator<<(const T &a, const T2 &b);
bitwise right shift a >> b Yes T T.:::operator>>(const T2 &b) const; T operator>>(const T &a, const T2 &b);
Uwagi

  • Wszystkie wbudowane operatory zwracają wartości, a większość przeciążeń zdefiniowanych przez użytkownika również zwraca wartości, tak że operatory zdefiniowane przez użytkownika mogą być używane w taki sam sposób jak operatory wbudowane. Jednakże, w przeciążeniu operatora zdefiniowanego przez użytkownika, jako typ zwracany może być użyty dowolny typ (w tym void). W szczególności, przeciążenia wstawiania strumienia i pobierania strumienia operator<< i operator>> zwracają T&.
  • T2 może być dowolnym typem, w tym T

  • 1 Objaśnienie
    • 1.1 Konwersje
    • 1.2 Przepełnienia
    • 1.3 Środowisko zmiennoprzecinkowe
    • 1.4 Skurcz zmiennoprzecinkowy
    • 1.5 Operatory arytmetyki jednoargumentowej
    • 1.6 Operatory addytywne
    • 1.7 Operatory multiplikatywne
    • 1.8 Bitowe operatory logiczne
    • 1.9 Operatory przesunięć bitowych
  • 2 Biblioteka standardowa
    • 2.1 Operatory arytmetyki unarnej
    • 2.2 Operatory addytywne
    • 2.3 Operatory multiplikatywne
    • 2.4 Operatory logiczne bitowe
    • 2.5 Operatory przesunięć bitowych
    • 2.6 Operatory wstawiania/wyciągania strumienia
  • 3 Raporty o wadach
  • 4 Zobacz także

Objaśnienie

Wszystkie operatory arytmetyczne obliczają wynik określonej operacji arytmetycznej i zwracają jej wynik. Argumenty nie są modyfikowane.

Konwersje

Jeśli operand przekazany operatorowi arytmetycznemu jest typu integralnego lub nieskorelowanego typu wyliczeniowego, to przed jakimkolwiek innym działaniem (ale po konwersji z wartości na wartość, jeśli ma to zastosowanie) operand przechodzi promocję integralną. Jeśli operand ma typ tablicowy lub funkcyjny, stosowane są konwersje typu tablica na wskaźnik i funkcja na wskaźnik.

Dla operatorów binarnych (z wyjątkiem przesunięć), jeśli promowane operandy mają różne typy, stosowany jest dodatkowy zestaw niejawnych konwersji, znany jako zwykłe konwersje arytmetyczne, których celem jest wyprodukowanie wspólnego typu (dostępnego również przez cechę typu std::common_type). Jeśli, przed jakąkolwiek promocją integralną, jeden z operandów jest typu wyliczeniowego, a drugi operand jest typu zmiennoprzecinkowego lub innego typu wyliczeniowego, to zachowanie to jest zdeprecjonowane. (od C++20)

  • Jeśli jeden z operandów ma typ wyliczeniowy, to konwersja nie jest wykonywana: drugi operand i typ zwracany muszą mieć ten sam typ
  • W przeciwnym razie, jeśli którykolwiek z operandów jest long double, drugi operand jest konwertowany na long double
  • W przeciwnym razie, jeśli którykolwiek z operandów jest double, drugi operand jest konwertowany na double
  • W przeciwnym razie, Jeśli którykolwiek z operandów jest float, drugi operand jest konwertowany na float
  • W przeciwnym razie operand ma typ integer (ponieważ bool, char, char8_t, char16_t, char32_t, wchar_t i unscoped enumeration zostały promowane w tym momencie) i integralne konwersji są stosowane do produkcji wspólnego typu, jak poniżej:
  • Jeśli oba operandy są podpisane lub oba są niepodpisane, operand o mniejszym stopniu konwersji jest konwertowany na operand o większym stopniu konwersji liczby całkowitej
  • W przeciwnym razie, jeśli stopień konwersji niepodpisanego operandu jest większy lub równy stopniowi konwersji podpisanego operandu, podpisany operand jest konwertowany na typ niepodpisanego operandu.
  • W przeciwnym razie, jeśli typ podpisanego operandu może reprezentować wszystkie wartości niepodpisanego operandu, niepodpisany operand jest konwertowany na typ podpisanego operandu
  • W przeciwnym razie oba operandy są konwertowane na niepodpisany odpowiednik typu podpisanego operandu.

Ranga konwersji powyżej wzrasta w kolejności bool, signed char, short, int, long, long long. Ranga każdego niepodpisanego typu jest równa randze odpowiadającego mu podpisanego typu. Ranga char jest równa randze podpisanego char i unsigned char. Rangi char8_t, char16_t, char32_t i wchar_t są równe rangom ich podstawowych typów.

Przepełnienia

Unsigned integer arithmetic jest zawsze wykonywany modulo 2n
gdzie n jest liczbą bitów w tej konkretnej liczbie całkowitej. Np. dla unsigned int, dodanie jedynki do UINT_MAX daje 0, a odjęcie jedynki od 0 daje UINT_MAX.

Gdy podpisana operacja arytmetyczna na liczbach całkowitych przepełnia się (wynik nie mieści się w typie wynikowym), zachowanie jest niezdefiniowane, – możliwe przejawy takiej operacji obejmują:

  • owija się zgodnie z regułami reprezentacji (typowo 2’s complement),
  • wpada w pułapkę – na niektórych platformach lub ze względu na opcje kompilatora (np.np. -ftrapv w GCC i Clang),
  • nasyca się do wartości minimalnej lub maksymalnej (na wielu DSP),
  • jest całkowicie zoptymalizowany przez kompilator.

Środowisko zmiennoprzecinkowe

Jeśli #pragma STDC FENV_ACCESS jest obsługiwana i ustawiona na ON, wszystkie operatory arytmetyki zmiennoprzecinkowej przestrzegają bieżącego kierunku zaokrąglania zmiennoprzecinkowego i zgłaszają błędy arytmetyki zmiennoprzecinkowej, jak określono w math_errhandling, chyba że są częścią inicjalizatora statycznego (w tym przypadku wyjątki zmiennoprzecinkowe nie są zgłaszane, a trybem zaokrąglania jest nearest)

Skurcz zmiennoprzecinkowy

Jeśli #pragma STDC FP_CONTRACT jest obsługiwana i ustawiona na OFF, cała arytmetyka zmiennoprzecinkowa może być wykonywana tak, jakby wyniki pośrednie miały nieskończony zakres i precyzję, to znaczy, dozwolone są optymalizacje, które pomijają błędy zaokrągleń i wyjątki zmiennoprzecinkowe. Na przykład, C++ pozwala na implementację (x*y) + z za pomocą pojedynczej instrukcji multiply-add CPU lub optymalizację a = x*x*x; jako tmp = x *x; a = tmp*tmp.

Niezwiązane z kontraktowaniem, pośrednie wyniki arytmetyki zmiennoprzecinkowej mogą mieć zakres i precyzję, która jest inna niż wskazana przez jej typ, zobacz FLT_EVAL_METHOD

Ogólnie, standard C++ nie gwarantuje dokładności operacji zmiennoprzecinkowych.

Operatory arytmetyczne jednoargumentowe

Wyrażenia operatorów arytmetycznych jednoargumentowych mają postać

+ wyrażenie . (1)
- wyrażenie (2)
1) jednoargumentowy plus (promocja).
Dla operatora wbudowanego, wyrażenie musi mieć typ arytmetyczny, wyliczeniowy lub wskaźnikowy. 2) unarny minus (negacja).
W przypadku operatora wbudowanego, wyrażenie musi mieć typ arytmetyczny lub nieskorelowany typ wyliczeniowy. Promocja całkowa jest wykonywana na operandzie i określa typ wyniku.

Wbudowany operator unarny plus zwraca wartość swojego operandu. Jedyną sytuacją, gdy nie jest to no-op, jest gdy operand ma typ integralny lub typ wyliczeniowy, który jest zmieniany przez promocję integralną, np. konwertuje char na int lub gdy operand podlega konwersji lvalue-to-rvalue, array-to-pointer lub function-to-pointer.

Wbudowany jednoargumentowy operator minus oblicza minus swojego promowanego operandu. Dla unsigned a, wartością -a jest 2b
-a, gdzie b jest liczbą bitów po promocji.

W rozdzielczości przeciążania przeciwko operatorom zdefiniowanym przez użytkownika, dla każdego promowanego typu arytmetycznego A i dla każdego typu T, następujące sygnatury funkcji uczestniczą w rozdzielczości przeciążania:

A operator+(A)

T* operator+(T*)

A operator-.(A)

Run this code
#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; std::cout << "size of array: " << sizeof a << '\n' << "size of pointer: " << sizeof +a << '\n';}

Output:

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

Operatory addytywne

Wyrażenia binarnych operatorów arytmetycznych addytywnych mają postać

lhs + rhs. (1)
lhs - rhs (2)
1) dodawanie
Dla wbudowanegow operator, lhs i rhs muszą być jedną z następujących wartości:

  • oba mają typ arytmetyczny lub unscoped enumeration. W tym przypadku, zwykłe konwersje arytmetyczne są wykonywane na obu operandach i określają typ wyniku.
  • jeden jest wskaźnikiem do całkowicie zdefiniowanego typu obiektu, drugi ma typ integralny lub unscoped enumeration. W tym przypadku, typ wyniku ma typ wskaźnika.
2) odejmowanie
Dla operatora wbudowanego, lhs i rhs muszą być jednym z następujących:

  • oba mają typ arytmetyczny lub unscoped enumeration. W tym przypadku, zwykłe konwersje arytmetyczne są wykonywane na obu operandach i określają typ wyniku.
  • lhs jest wskaźnikiem do całkowicie zdefiniowanego typu obiektu, rhs ma typ integralny lub unscoped enumeration. W tym przypadku, typ wyniku ma typ wskaźnika.
  • oba są wskaźnikami do tych samych całkowicie zdefiniowanych typów obiektów, ignorując kwalifikatory cv. W tym przypadku typem wynikowym jest std::ptrdiff_t.

W przypadku operandów typu arytmetycznego lub wyliczeniowego, wynikiem operatora binarnego plus jest suma operandów (po zwykłych konwersjach arytmetycznych), a wynikiem operatora binarnego minus jest wynik odjęcia drugiego operandu od pierwszego (po zwykłych konwersjach arytmetycznych), z wyjątkiem tego, że jeśli typ obsługuje arytmetykę zmiennoprzecinkową IEEE (zobacz std::numeric_limits::is_iec559),

  • jeśli jeden z operandów jest NaN, wynik jest NaN
  • nieskończoność minus nieskończoność jest NaN i FE_INVALID jest podniesiony
  • nieskończoność plus ujemna nieskończoność jest NaN i FE_INVALID jest podniesiony

Jeśli którykolwiek z operandów jest wskaźnikiem, stosuje się następujące zasady:

  • Wskaźnik do obiektu niebędącego tablicą jest traktowany jako wskaźnik do pierwszego elementu tablicy o rozmiarze 1.
  • Jeśli wskaźnik P wskazuje na i element tablicy, to wyrażenia P+n, n+P i P-n są wskaźnikami tego samego typu, które wskazują odpowiednio na i+n, i+n i i-n element tej samej tablicy. Wynikiem dodawania wskaźników może być również wskaźnik jeden za końcem (czyli wskaźnik P taki, że wyrażenie P-1 wskazuje na ostatni element tablicy). Wszelkie inne sytuacje (to znaczy, próby wygenerowania wskaźnika, który nie wskazuje na element tej samej tablicy lub jeden za końcem) wywołują niezdefiniowane zachowanie.
  • Jeśli wskaźnik P wskazuje na i element tablicy, a wskaźnik Q wskazuje na j element tej samej tablicy, to wyrażenie P-Q ma wartość i-j, jeśli wartość mieści się w std::ptrdiff_t. Oba operandy muszą wskazywać na elementy tej samej tablicy (lub jeden za końcem), w przeciwnym razie zachowanie jest niezdefiniowane. Jeśli wynik nie mieści się w std::ptrdiff_t, zachowanie jest niezdefiniowane.
  • W każdym przypadku, jeśli typ wskazywany jest różny od typu elementu tablicy, pomijając kwalifikacje cv, na każdym poziomie, jeśli elementy są same wskaźnikami, zachowanie arytmetyki wskaźnikowej jest niezdefiniowane. W szczególności, arytmetyka wskaźnikowa ze wskaźnikiem do bazy, który wskazuje na element tablicy obiektów pochodnych jest niezdefiniowana.
  • Jeśli wartość 0 jest dodawana lub odejmowana od wskaźnika, wynikiem jest wskaźnik, niezmieniony. Jeśli dwa wskaźniki wskazują na ten sam obiekt lub oba są o jeden za końcem tej samej tablicy, lub oba są wskaźnikami null, to wynik odejmowania jest równy (std::ptrdiff_t)0.

Te operatory arytmetyki wskaźników pozwalają wskaźnikom spełniać wymagania LegacyRandomAccessIterator.

W rozdzielczości przeciążania przeciwko operatorom zdefiniowanym przez użytkownika, dla każdej pary promowanych typów arytmetycznych L i R oraz dla każdego typu obiektu T, następujące sygnatury funkcji uczestniczą w rozdzielczości przeciążania:

LR operator+(L, R)

LR operator-(L, R)

T* operator+(T*, std::ptrdiff_t)

T* operator+(std::ptrdiff_t, T*)

T* operator-(T*, std::ptrdiff_t)

std::ptrdiff_t operator-(T*, T*)

gdzie LR jest wynikiem zwykłej konwersji arytmetycznej na . konwersji arytmetycznej na L i R

Uruchom ten kod
#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 = {'a', 'b', 'c', 'd'}; char* p = &a; std::cout << "Pointer addition examples: " << *p << *(p + 2) << *(2 + p) << *(p - 1) << '\n'; char* p2 = &a; std::cout << "Pointer difference: " << p2 - p << '\n';}

Wyjście:

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

Operatory multiplikatywne

Binarne wyrażenia operatorów arytmetycznych multiplikatywnych mają postać

.

lhs * rhs (1)
lhs / rhs (2)
lhs % rhs (3)
1) mnożenie
Dla operatora wbudowanego
.w operator, lhs i rhs muszą mieć typ arytmetyczny lub nieobsługiwany typ wyliczeniowy.
2) dzielenie
Dla operatora wbudowanego, lhs i rhs muszą mieć zarówno typ arytmetyczny jak i wyliczeniowy.
3) remainder
Dla wbudowanego operatora, lhs i rhs muszą mieć integralny lub unscoped typ wyliczeniowy

Dla wszystkich trzech operatorów, zwykłe konwersje arytmetyczne są wykonywane na obu operandach i określają typ wyniku.

Operator binarny * wykonuje mnożenie swoich operandów (po zwykłych konwersjach arytmetycznych), z wyjątkiem tego, że dla mnożenia zmiennoprzecinkowego,

  • mnożenie NaN przez dowolną liczbę daje NaN
  • mnożenie nieskończoności przez zero daje NaN i podnoszona jest wartość FE_INVALID

Operator binarny / dzieli pierwszy operand przez drugi (po zwykłych konwersjach arytmetycznych).

Dla operandów całkowitych daje iloraz algebraiczny.

Licznik jest zaokrąglany w kierunku określonym przez implementację.

(do C++11)

Ci iloraz jest obcinany w kierunku zera (część ułamkowa jest odrzucana).

(od C++11)

Jeśli drugi operand jest zerem, zachowanie jest niezdefiniowane, z wyjątkiem tego, że jeśli ma miejsce dzielenie zmiennoprzecinkowe, a typ obsługuje arytmetykę zmiennoprzecinkową IEEE (patrz std::numeric_limits::is_iec559), to:

  • jeśli jeden operand jest NaN, wynikiem jest NaN
  • dzielenie niezerowej liczby przez ±0.0 daje poprawnie podpisaną nieskończoność i podnoszona jest wartość FE_DIVBYZERO
  • dzielenie 0.0 przez 0.0 daje NaN i podnoszona jest wartość FE_INVALID

Operator binarny % daje resztę z dzielenia liczby całkowitej pierwszego operandu przez drugi (po zwykłych konwersjach arytmetycznych; zauważ, że typy operandów muszą być typami całkowitymi). Jeśli iloraz a/b jest reprezentowalny w typie wynikowym, to (a/b)*b + a%b == a. Jeśli drugi operand jest zerem, to zachowanie jest niezdefiniowane. Jeśli iloraz a/b nie jest reprezentowalny w typie wynikowym, zachowanie zarówno a/b jak i a%b jest niezdefiniowane (to znaczy INT_MIN%-1 jest niezdefiniowane w systemach 2’s complement)

Uwaga: Do C++11, jeśli jeden lub oba operandy operatora binarnego % były ujemne, znak reszty był definiowany przez implementację, ponieważ zależy od kierunku zaokrąglania przy dzieleniu liczb całkowitych. Funkcja std::div zapewniała dobrze zdefiniowane zachowanie w takim przypadku.

Uwaga: dla reszt zmiennoprzecinkowych, zobacz std::remainder i std::fmod.

W rozdzielczości przeciążania przeciwko operatorom zdefiniowanym przez użytkownika, dla każdej pary promowanych typów arytmetycznych LA i RA oraz dla każdej pary promowanych typów całkowych LI i RI następujące sygnatury funkcji uczestniczą w rozdzielczości przeciążania:

LRA operator*(LA, RA)

LRA operator/(LA, RA)

LRI operator%(LI, RI)

gdzie LRx jest wynikiem zwykłej konwersji konwersji arytmetycznych na Lx i Rx

Uruchom ten kod
#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';}

Wyjście:

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

Bitowe operatory logiczne

Wyrażenia bitowych operatorów arytmetycznych mają postać

.

.

~ rhs (1)
lhs & rhs (2)
lhs | rhs (3)
lhs ^ rhs (4)
1) bitowe NOT
2) bitowe AND
3) bitowe OR
4) bitowe XOR
Dla wbudowanych operatorów.w operatory, lhs i rhs muszą mieć typ całkowity lub nieskopijny typ wyliczeniowy. Zwykłe konwersje arytmetyczne są wykonywane na obu operandach i określają typ wyniku.

Wynikiem operatora~ jest bitowa wartość NOT (dopełnienie jedynki) argumentu (po promocji). Wynikiem operatora& jest bitowa wartość AND operandów (po zwykłych konwersjach arytmetycznych). Wynikiem operatora| jest wartość bitowa OR operandów (po zwykłej konwersji arytmetycznej). Wynikiem operatora^ jest bitowa wartość XOR operandów (po zwykłych konwersjach arytmetycznych)

W rozwiązywaniu przeciążeń względem operatorów zdefiniowanych przez użytkownika, dla każdej pary promowanych typów całkowych L i R w rozwiązywaniu przeciążeń uczestniczą następujące sygnatury funkcji:

R operator~(R)

LR operator&(L, R)

LR operator^(L, R)

LR operator|(L, R)

gdzie LR jest wynikiem zwykłej konwersji konwersji arytmetycznej na L i R

Uruchom ten kod
#include <iostream>int main(){ std::cout << std::hex << std::showbase; uint16_t mask = 0x00f0; uint32_t a = 0x12345678; std::cout << "Value: " << a << " mask: " << mask << '\n' << "Setting bits: " << (a | mask) << '\n' << "Clearing bits: " << (a & ~mask) << '\n' << "Selecting bits: " << (a & mask) << '\n';}

Wyjście:

Value: 0x12345678 mask: 0xf0Setting bits: 0x123456f8Clearing bits: 0x12345608Selecting bits: 0x70

Operatory przesunięcia bitowego

Wyrażenia bitowych operatorów przesunięcia mają postać

.

lhs << rhs (1)
lhs >> rhs (2)
1) przesunięcie w lewo lhs o bity rhs
2) przesunięcie w prawo lhs o bity rhs
Dla wbudowanych w operatoryw operatory, lhs i rhs muszą mieć typ całkowity lub nieskoszarowany typ wyliczeniowy. Integralne promocje są wykonywane na obu operandach.

Typem zwracanym jest typ lewego operandu po promocjach integralnych.

Dla unsigned a, wartość a << b jest wartością a * 2b
, zredukowaną modulo 2N
gdzie N jest liczbą bitów w zwracanym typie (to jest, bitowe przesunięcie w lewo jest wykonywane, a bity, które są przesunięte poza typ docelowy są odrzucane).

Dla podpisanych i nieujemnych a, jeśli a * 2b
jest reprezentowalne w niepodpisanej wersji typu zwrotnego, to ta wartość, przekonwertowana na podpisaną, jest wartością a << b (to czyni legalnym tworzenie INT_MIN jako 1<<31); w przeciwnym razie zachowanie jest niezdefiniowane.

Dla ujemnych a, zachowanie a << b jest niezdefiniowane.

Dla niepodpisanych a oraz dla podpisanych i nieujemnych a, wartość a >> b jest częścią całkowitą a/2b
.

Dla ujemnych a, wartość a >> b jest zdefiniowana w implementacji (w większości implementacji, to wykonuje arytmetyczne przesunięcie w prawo, tak że wynik pozostaje ujemny).

(do C++20)

Wartość a << b jest unikalną wartością kongruentną do a * 2b
modulo 2N
gdzie N jest liczbą bitów w typie zwrotnym (to jest, bitowe przesunięcie w lewo jest wykonywane, a bity, które zostaną przesunięte poza typ docelowy są odrzucane).

Wartością a >> b jest a/2b
, zaokrąglone w dół (innymi słowy, przesunięcie w prawo na podpisanym a jest arytmetycznym przesunięciem w prawo).

(od C++20)

W każdym przypadku, jeśli wartość prawego operandu jest ujemna lub jest większa lub równa liczbie bitów w promowanym lewym operandzie, zachowanie jest niezdefiniowane.

W rozdzielczości przeciążania przeciwko operatorom zdefiniowanym przez użytkownika, dla każdej pary promowanych typów integralnych L i R, następujące sygnatury funkcji uczestniczą w rozdzielczości przeciążania:

L operator<<(L, R)

L operator>>(L, R)

Run this code
#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' // overflow in unsigned << "0x10 << 10 = " << (c << 10) << '\n'; // char is promoted to int long long ll = -1000; std::cout << std::dec << "-1000 >> 1 = " << (ll >> ONE) << '\n';}

Output:

0x123 << 1 = 0x2460x123 << 63 = 0x80000000000000000x10 << 10 = 0x4000-1000 >> 1 = -500

Biblioteka standardowa

Operatory arytmetyczne są przeciążone dla wielu typów biblioteki standardowej.

Operatory arytmetyczne jednoargumentowe

implementuje jednoargumentowe + i jednoargumentowe -.
(public member function of std::chrono::duration<Rep,Period>)

stosuje operatory jednoargumentowe do liczb złożonych
(function template)

stosuje jednoargumentowy operator arytmetyczny do każdego elementu tablicy wartości
(public member function of std::valarray<T>)

. Operatory addytywne

wykonuje operacje dodawania i odejmowania obejmujące punkt czasowy
(szablon funkcji)

implementuje operacje arytmetyczne z czasami trwania jako argumentami
(szablon funkcji)

dodaje lub odejmuje year_month_day i pewną liczbę lat lub miesięcy
(funkcja członka publicznego std::chrono::year_month_day)

konkatenuje dwa ciągi znaków lub ciąg znaków i znak
(szablon funkcji)

zwiększa lub zmniejsza iterator
(funkcja członka publicznego std::reverse_iterator<Iter>)

rozwija lub zmniejsza iterator
(funkcja członka publicznego std::move_iterator<Iter>)

wykonuje arytmetykę liczb zespolonych na dwóch wartościach zespolonych lub kompleksie i skalarze
(szablon funkcji)

stosuje operatory binarne do każdego elementu dwóch tablic wartości, lub tablicy wartości i wartości
(szablon funkcji)

Operatory multiplikatywne

implementuje operacje arytmetyczne z czasami jako argumentami
(szablon funkcji)

wykonuje arytmetykę liczb zespolonych na dwóch wartościach zespolonych lub kompleksie i skalarze
(szablon funkcji)

stosuje operatory binarne do każdego elementu dwóch tablic wartości, lub tablicę wartości i wartość
(szablon funkcji)

Bitowe operatory logiczne

wykonuje operatory binarne AND, OR, XOR i NOT
(funkcja członka publicznego std::bitset<N>)

wykonuje binarne operacje logiczne na zbiorach bitów
(szablon funkcji)

stosuje jednoargumentowy operator arytmetyczny do każdego elementu tablicy wartości
(funkcja członka publicznego std::valarray<T>)

stosuje operatory binarne do każdego elementu dwóch tablic wartości, lub tablicę wartości i wartość
(szablon funkcji)

Operatory przesunięcia bitowego

stosuje operatory binarne do każdego elementu dwóch tablic wartości, lub tablicy wartości i wartości
(szablon funkcji)

wykonuje operatory binarne przesunięcia w lewo i przesunięcia w prawo
(funkcja członka publicznego std::bitset<N>)

Operatory wstawiania/wyciągania strumienia

Przez całą bibliotekę standardową, operatory przesunięcia bitowego są powszechnie przeciążane strumieniem I/O (std::ios_base& lub jedną z klas pochodnych od niego) zarówno jako lewy operand, jak i typ zwracany. Takie operatory są znane jako operatory wstawiania strumienia i wyciągania strumienia:

wyodrębnia dane sformatowane
(funkcja członka publicznego std::basic_istream<CharT,Traits>)

wyodrębnia znaki i tablice znaków
(szablon funkcji)

wstawia dane sformatowane
(funkcja członka publicznego std::basic_ostream<CharT,Traits>)

wstawia dane znaków
(szablon funkcji)

. serializuje i deserializuje liczbę złożoną
(szablon funkcji)

wykonuje strumieniowe wprowadzanie i wyprowadzanie zbiorów bitów
(szablon funkcji)

wykonuje strumieniowe wprowadzanie i wyprowadzanie ciągów znaków
(szablon funkcji)

wykonuje strumieniowe wprowadzanie i wyprowadzanie pseudo-random number engine
(function template)

performs stream input and output on pseudo-random number distribution
(function template)

Defect reports

Następujące raporty o wadach zmieniających zachowanie zostały zastosowane z mocą wsteczną do wcześniej opublikowanych standardów C++.

DR Applied to Behavior as published Correct behavior
CWG 1457 C++98 shifting the leftmost 1 bit of a positive signed value into the sign bit was UB made well-zdefiniowane

Zobacz także

Pierwszeństwo operatorów

Przeciążanie operatorów

Operatory wspólne
przypisanie . increment
decrement
arytmetyczne logiczne porównania member
access
inne

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

a(…)
a, b
? :

Operatory specjalne

static_cast konwertuje jeden typ na inny powiązany typ
dynamic_cast konwertuje w obrębie hierarchii dziedziczenia
const_cast dodaje lub usuwa kwalifikatory cv
reinterpret_cast konwertuje typ na typ niepowiązany
C-style cast konwertuje jeden typ na inny przez mieszankę static_cast, const_cast, i reinterpret_cast
new tworzy obiekty z dynamicznym czasem przechowywania
delete niszczy obiekty wcześniej utworzone przez nowe wyrażenie i zwalnia uzyskany obszar pamięci
sizeof zapytuje o rozmiar typu
sizeof… zapytuje o rozmiar pakietu parametrów (od C++11)
typeid zapytuje o informacje o typie
noexcept sprawdza, czy wyrażenie może rzucić wyjątek (od C++11)
alignof zapytuje o wymagania wyrównania typu (od C++11)

Dokumentacja C dla operatorów arytmetycznych

Dodaj komentarz