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 |
Definition
Usual arithmetic conversions are defined as follows:
Stage 1
Applies lvalue-to-rvalue conversion to both operands, the resulting prvalues are used in place of the original operands for the remaining process.
Stage 2
|
(since C++11) |
Stage 3
|
(since C++26) |
Stage 4
- If either operand is of floating-point 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 non-floating-point type, that operand is converted to the type of the other operand.
- Otherwise, if the floating-point 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 floating-point 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.
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
T1andT2are the same type,Cis that type. -
Otherwise, if
T1andT2are both signed integer types or both unsigned integer types,Cis the type of greater integer conversion rank . -
Otherwise, one type between
T1andT2is an signed integer typeS, the other type is an unsigned integer typeU. Apply the following rules:
-
-
If the integer conversion rank of
Uis greater than or equal to the integer conversion rank ofS,CisU. -
Otherwise, if
Scan represent all of the values ofU,CisS. -
Otherwise,
Cis 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 floating-point type, this behavior is deprecated. |
(since C++20)
(until C++26) |
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 implementation-defined underlying type.
|
(since C++11) |
-
For all integer types
T1,T2, andT3, ifT1has greater rank thanT2andT2has greater rank thanT3, thenT1has greater rank thanT3.
The integer conversion rank is also used in the definition of integral promotion .
Floating-point conversion rank and subrank
Floating-point conversion rank
Every floating-point type has a floating-point conversion rank defined as follows:
-
The ranks of the standard floating-point types decrease in order:
- long double
- double
- float
|
(since C++23) |
Floating-point conversion subrankFloating-point types that have equal floating-point conversion ranks are ordered by floating-point conversion subrank . The subrank forms a total order among types with equal ranks.
The types
|
(since C++23) |
Usage
The floating-point conversion rank and subrank are also used to
- determine whether a conversion between different floating-point 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 floating-point type if the arguments of different floating-point types are passed to common or special math functions.
Defect reports
The following behavior-changing 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 lvalue-to-rvalue conversions first |
| CWG 2528 | C++20 |
the three-way comparison between
unsigned
char
and unsigned int is ill-formed 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
floating-point 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 three-way comparison ill-formed.
- ↑ 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 three-way comparison is well-formed.