Usual arithmetic conversions
Many binary operators that expect operands of arithmetic or enumeration type cause conversions and yield result types in a similar way. The purpose is to yield a common type, which is also the type of the result. This pattern is called the usual arithmetic conversions.
Contents 
[edit] Definition
Usual arithmetic conversions are defined as follows:
[edit] Stage 1
Applies lvaluetorvalue conversion to both operands, the resulting prvalues are used in place of the original operands for the remaining process.
[edit] Stage 2

(since C++11) 
[edit] Stage 3

(since C++26) 
[edit] Stage 4
 If either operand is of floatingpoint type, the following rules are applied:
 If both operands have the same type, no further conversion will be performed.
 Otherwise, if one of the operands is of a nonfloatingpoint type, that operand is converted to the type of the other operand.
 Otherwise, if the floatingpoint conversion ranks of the types of the operands are ordered but(since C++23) not equal, then the operand of the type with the lesser floatingpoint conversion rank is converted to the type of the other operand.

(since C++23) 
 Otherwise, both operands are of integer types, proceed to the next stage.
[edit] Stage 5
Both operands are converted to a common type C
. Given the types T1
and T2
as the promoted type (under the rules of integral promotions) of the operands, the following rules are applied to determine C
:
 If
T1
andT2
are the same type,C
is that type.  Otherwise, if
T1
andT2
are both signed integer types or both unsigned integer types,C
is the type of greater integer conversion rank.  Otherwise, one type between
T1
andT2
is an signed integer typeS
, the other type is an unsigned integer typeU
. Apply the following rules:
 If the integer conversion rank of
U
is greater than or equal to the integer conversion rank ofS
,C
isU
.  Otherwise, if
S
can represent all of the values ofU
,C
isS
.  Otherwise,
C
is the unsigned integer type corresponding toS
.
 If the integer conversion rank of
If one operand is of enumeration type and the other operand is of a different enumeration type or a floatingpoint type, this behavior is deprecated. 
(since C++20) (until C++26) 
[edit] Integer conversion rank
Every integer type has an integer conversion rank defined as follows:
 No two signed integer types other than char and signed char (if char is signed) have the same rank, even if they have the same representation.
 The rank of a signed integer type is greater than the rank of any signed integer type with a smaller width.
 The ranks of the following integer types decrease in order:

(since C++11) 
 long
 int
 short
 signed char
 The rank of any unsigned integer type equals the rank of the corresponding signed integer type.

(since C++11) 
 The rank of bool is less than the rank of all standard integer types.
 The ranks of encoding character types (char , char8_t(since C++20), char16_t, char32_t,(since C++11) and wchar_t) equal the ranks of their underlying types, which means:
 The rank of char equals the rank of signed char and unsigned char.

(since C++20) 

(since C++11) 
 The rank of wchar_t equals the rank of its implementationdefined underlying type.

(since C++11) 
 For all integer types
T1
,T2
, andT3
, ifT1
has greater rank thanT2
andT2
has greater rank thanT3
, thenT1
has greater rank thanT3
.
The integer conversion rank is also used in the definition of integral promotion.
[edit] Floatingpoint conversion rank and subrank
[edit] Floatingpoint conversion rank
Every floatingpoint type has a floatingpoint conversion rank defined as follows:
 The ranks of the standard floatingpoint types decrease in order:
 long double
 double
 float

(since C++23) 
Floatingpoint conversion subrankFloatingpoint types that have equal floatingpoint conversion ranks are ordered by floatingpoint conversion subrank. The subrank forms a total order among types with equal ranks. The types 
(since C++23) 
[edit] Usage
The floatingpoint conversion rank and subrank are also used to
 determine whether a conversion between different floatingpoint types can be implicit or is a narrowing conversion,
 distinguish the conversion sequences in overload resolution,

(since C++23) 
 determine whether std::complex's converting constructor is explicit, or
 determine the common floatingpoint type if the arguments of different floatingpoint types are passed to common or special math functions.
[edit] Defect reports
The following behaviorchanging defect reports were applied retroactively to previously published C++ standards.
DR  Applied to  Behavior as published  Correct behavior 

CWG 1642  C++98  usual arithmetic conversions might involve lvalues  applies lvaluetorvalue conversions first 
CWG 2528  C++20  the threeway comparison between unsigned char and unsigned int is illformed because of the intermediate integral promotion^{[1]} 
determines the common type based on the promoted types, without actually promoting the operands^{[2]} 
CWG 2892  C++98  when both operands are of the same floatingpoint type, the meaning of “no further conversion is needed” was unclear 
changed to “no further conversion will be performed” 
 ↑ Before the resolution, unsigned char is promoted to int at the beginning of stage 5, then it is converted to unsigned int. However, the latter conversion is narrowing, which makes the threeway comparison illformed.
 ↑ After the resolution, the common type is still unsigned int. The difference is that unsigned char is directly converted to unsigned int without the intermediate integral promotion. The conversion is not narrowing and hence the threeway comparison is wellformed.