Usual arithmetic conversions
Многие бинарные операторы, которые ожидают операнды арифметического или перечислимого типа, вызывают преобразования и выдают типы результатов схожим образом. Цель состоит в получении общего типа, который также является типом результата. Эта схема называется обычными арифметическими преобразованиями .
Содержание |
Определение
Обычные арифметические преобразования определяются следующим образом:
Этап 1
Применяет преобразование lvalue-в-rvalue к обоим операндам, полученные prvalue используются вместо исходных операндов в последующем процессе.
Этап 2
|
(since C++11) |
Этап 3
|
(начиная с C++26) |
Этап 4
- Если любой из операндов имеет тип с плавающей точкой , применяются следующие правила:
-
- Если оба операнда имеют одинаковый тип, дальнейшее преобразование не выполняется.
- В противном случае, если один из операндов имеет не-вещественный тип, этот операнд преобразуется к типу другого операнда.
- В противном случае, если ранги преобразования вещественных типов типов операндов упорядочены, но (начиная с C++23) не равны, то операнд типа с меньшим рангом преобразования вещественных типов преобразуется к типу другого операнда.
|
(начиная с C++23) |
- В противном случае, если оба операнда имеют целочисленные типы, переходите к следующему этапу.
Этап 5
Оба операнда преобразуются к общему типу
C
. При заданных типах
T1
и
T2
как продвинутых типах (
согласно правилам целочисленных преобразований
) операндов, применяются следующие правила для определения
C
:
-
Если
T1иT2являются одинаковыми типами,Cбудет этим типом. -
В противном случае, если
T1иT2являются одновременно знаковыми целочисленными типами или беззнаковыми целочисленными типами,Cбудет типом с более высоким рангом целочисленного преобразования . -
В противном случае, один из типов между
T1иT2является знаковым целочисленным типомS, а другой тип - беззнаковым целочисленным типомU. Примените следующие правила:
-
-
Если целочисленный ранг преобразования
Uбольше или равен целочисленному рангу преобразованияS,CявляетсяU. -
Иначе, если
Sможет представить все значенияU,CявляетсяS. -
Иначе,
Cявляется беззнаковым целочисленным типом, соответствующимS.
-
Если целочисленный ранг преобразования
|
Если один операнд имеет тип перечисления, а другой операнд имеет другой тип перечисления или тип с плавающей точкой, такое поведение устарело. |
(since C++20)
(until C++26) |
Ранг преобразования целочисленных типов
Каждый целочисленный тип имеет ранг целочисленного преобразования , определяемый следующим образом:
- Никакие два знаковых целочисленных типа, кроме char и signed char (если char является знаковым), не имеют одинакового ранга, даже если они имеют одинаковое представление.
- Ранг знакового целочисленного типа больше ранга любого знакового целочисленного типа с меньшей шириной.
- Ранги следующих целочисленных типов уменьшаются в порядке:
|
(начиная с C++11) |
-
- long
- int
- short
- signed char
- Ранг любого беззнакового целочисленного типа равен рангу соответствующего знакового целочисленного типа.
|
(since C++11) |
- Ранг типа bool меньше ранга всех стандартных целочисленных типов.
- Ранги кодирующих символьных типов ( char , char8_t (since C++20) , char16_t , char32_t , (since C++11) и wchar_t ) равны рангам их базовых типов , что означает:
-
- Ранг char равен рангу signed char и unsigned char .
|
(начиная с C++20) |
|
(начиная с C++11) |
-
- Ранг wchar_t равен рангу его определенного реализацией базового типа.
|
(since C++11) |
-
Для всех целочисленных типов
T1,T2иT3, еслиT1имеет более высокий ранг, чемT2, иT2имеет более высокий ранг, чемT3, тоT1имеет более высокий ранг, чемT3.
Ранг целочисленного преобразования также используется в определении integral promotion .
Ранг и подранг преобразования чисел с плавающей точкой
Ранг преобразования чисел с плавающей точкой
Каждый floating-point type имеет floating-point conversion rank , определяемый следующим образом:
-
Ранги стандартных типов с плавающей точкой убывают в следующем порядке:
- long double
- double
- float
|
(начиная с C++23) |
Подранг преобразования чисел с плавающей точкойТипы с плавающей точкой, имеющие равные ранги преобразования, упорядочиваются по подрангу преобразования чисел с плавающей точкой . Подранг формирует полный порядок среди типов с равными рангами.
Типы
|
(начиная с C++23) |
Использование
Ранг и подранг преобразования чисел с плавающей точкой также используются для
- определить, может ли преобразование между различными типами с плавающей запятой быть неявным или является сужающим преобразованием ,
- различать последовательности преобразований при разрешении перегрузки,
|
(начиная с C++23) |
- определить, является ли std::complex converting constructor явным, или
- определить общий тип с плавающей точкой, если аргументы разных типов с плавающей точкой передаются в common или special math functions.
Отчеты о дефектах
Следующие отчеты об изменениях поведения, влияющие на дефекты, были применены задним числом к ранее опубликованным стандартам C++.
| DR | Применяется к | Поведение в опубликованной версии | Корректное поведение |
|---|---|---|---|
| CWG 1642 | C++98 | обычные арифметические преобразования могут включать lvalues | сначала применяет преобразования lvalue-to-rvalue |
| CWG 2528 | C++20 |
трёхстороннее сравнение между
unsigned
char
и unsigned int некорректно из-за промежуточного целочисленного повышения [1] |
определяет общий тип на основе
повышенных типов, без фактического повышения операндов [2] |
| CWG 2892 | C++98 |
когда оба операнда имеют одинаковый
тип с плавающей точкой, значение "нет необходимости в дальнейших преобразованиях" было неясным |
изменено на "дальнейшие
преобразования выполняться не будут" |
- ↑ До принятия решения, unsigned char повышался до int в начале этапа 5, затем преобразовывался в unsigned int . Однако последнее преобразование является сужающим, что делает трёхстороннее сравнение некорректным.
- ↑ После принятия решения общий тип остаётся unsigned int . Разница заключается в том, что unsigned char напрямую преобразуется в unsigned int без промежуточного целочисленного повышения. Преобразование не является сужающим, следовательно, трёхстороннее сравнение корректно.