Namespaces
Variants

Usual arithmetic conversions

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

Многие бинарные операторы, которые ожидают операнды арифметического или перечислимого типа, вызывают преобразования и выдают типы результатов схожим образом. Цель состоит в получении общего типа, который также является типом результата. Эта схема называется обычными арифметическими преобразованиями .

Содержание

Определение

Обычные арифметические преобразования определяются следующим образом:

Этап 1

Применяет преобразование lvalue-в-rvalue к обоим операндам, полученные prvalue используются вместо исходных операндов в последующем процессе.

Этап 2

  • Если один из операндов имеет scoped enumeration type , преобразования не выполняются; если другой операнд не имеет тот же тип, выражение является некорректным.
  • В противном случае переходите к следующему этапу.
(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 является знаковым), не имеют одинакового ранга, даже если они имеют одинаковое представление.
  • Ранг знакового целочисленного типа больше ранга любого знакового целочисленного типа с меньшей шириной.
  • Ранги следующих целочисленных типов уменьшаются в порядке:
  • long long
(начиная с 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 .
  • Ранг char8_t равен рангу 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
  • Ранг типа с плавающей запятой T больше ранга любого типа с плавающей запятой, чье множество значений является собственным подмножеством множества значений T .
  • Два расширенных типа с плавающей запятой с одинаковым множеством значений имеют равные ранги.
  • Расширенный тип с плавающей запятой с таким же множеством значений, как у ровно одного cv-неквалифицированного стандартного типа с плавающей запятой, имеет ранг, равный рангу этого стандартного типа с плавающей запятой.
  • Расширенный тип с плавающей запятой с таким же множеством значений, как у более чем одного cv-неквалифицированного стандартного типа с плавающей запятой, имеет ранг, равный рангу double .
(начиная с C++23)


Подранг преобразования чисел с плавающей точкой

Типы с плавающей точкой, имеющие равные ранги преобразования, упорядочиваются по подрангу преобразования чисел с плавающей точкой . Подранг формирует полный порядок среди типов с равными рангами.

Типы std::float16_t , std::float32_t , std::float64_t , и std::float128_t ( типы с фиксированной шириной с плавающей точкой ) имеют больший подранг преобразования, чем любой стандартный тип с плавающей точкой с равным рангом преобразования. В остальных случаях порядок подранга преобразования определяется реализацией.

(начиная с 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 когда оба операнда имеют одинаковый
тип с плавающей точкой, значение "нет
необходимости в дальнейших преобразованиях" было неясным
изменено на "дальнейшие
преобразования выполняться не будут"
  1. До принятия решения, unsigned char повышался до int в начале этапа 5, затем преобразовывался в unsigned int . Однако последнее преобразование является сужающим, что делает трёхстороннее сравнение некорректным.
  2. После принятия решения общий тип остаётся unsigned int . Разница заключается в том, что unsigned char напрямую преобразуется в unsigned int без промежуточного целочисленного повышения. Преобразование не является сужающим, следовательно, трёхстороннее сравнение корректно.