# Usual arithmetic conversions

< cpp‎ | language

C++
 Compiler support Freestanding and hosted Language Standard library Standard library headers Named requirements Feature test macros (C++20) Language support library Concepts library (C++20) Metaprogramming library (C++11) Diagnostics library General utilities library Strings library Containers library Iterators library Ranges library (C++20) Algorithms library Numerics library Localizations library Input/output library Filesystem library (C++17) Regular expressions library (C++11) Concurrency support library (C++11) Technical specifications Symbols index External libraries

C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
 for range-for (C++11)
Jump statements
 goto - return
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications (until C++20)
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
 decltype (C++11) auto (C++11) alignas (C++11)
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
Implicit conversions - Explicit conversions
static_cast - dynamic_cast
const_cast - reinterpret_cast
Memory allocation
Classes
Class-specific function properties
 Virtual function override specifier (C++11) final specifier (C++11)
 explicit (C++11) static
Special member functions
 Default constructor Copy constructor Move constructor (C++11)
 Copy assignment Move assignment (C++11) Destructor
Templates
 Template specialization Parameter packs (C++11)
Miscellaneous

Expressions
General
Value categories (lvalue, rvalue, xvalue)
Order of evaluation (sequence points)
Constant expressions
Potentially-evaluated expressions
Primary expressions
Lambda expressions(C++11)
Literals
Integer literals
Floating-point literals
Boolean literals
Character literals including escape sequences
String literals
Null pointer literal(C++11)
User-defined literal(C++11)
Operators
 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&&b, !a a==b, a!=b, ab, a<=b, a>=b, a<=>b(C++20) a[b], *a, &a, a->b, a.b, a->*b, a.*b a(...), a,b, a?b:c
new-expression
delete-expression
throw-expression
alignof
sizeof
sizeof...(C++11)
typeid
noexcept(C++11)
Fold expressions(C++17)
Alternative representations of operators
Precedence and associativity
Default comparisons(C++20)
Conversions
Implicit conversions
Usual arithmetic conversions
const_cast
static_cast
reinterpret_cast
dynamic_cast
Explicit conversions: (T)a, T(a)
User-defined conversion

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:

 1) If either operand is of type long double, the other operand is converted to long double. 2) Otherwise, if either operand is double, the other operand is converted to double. 3) Otherwise, if either operand is float, the other operand is converted to float. 4) Otherwise, integral promotions are performed on both operands. 5) Then, if either operand is unsigned long, the other operand is converted to unsigned long. 6) Otherwise, if one operand is long and the other operand is unsigned int, then if a long can represent all the values of an unsigned int, the unsigned int operand is converted to a long; otherwise both operands are converted to unsigned long. 7) Otherwise, if either operand is long, the other operand is converted to long. 8) Otherwise, if either operand is unsigned int, the other operand is converted to unsigned int. (until C++11) 1) If either operand is of scoped enumeration type, no conversions are performed; if the other operand does not have the same type, the expression is ill-formed. 2) Otherwise, if either operand is of type long double, the other operand is converted to long double. 3) Otherwise, if either operand is double, the other operand is converted to double. 4) Otherwise, if either operand is float, the other operand is converted to float. 5) Otherwise, integral promotions are performed on both operands. Then the following rules are applied to the promoted operands: 1) If both operands have the same type, no further conversion is needed. 2) Otherwise, if both operands have signed integer types or both have unsigned integer types, the operand with the type of lesser integer conversion rank is converted to the type of the other operand. 3) Otherwise, one operand is of an signed integer type S, the other operand is of an unsigned integer type U. The follwing rules apply: 1) If the integer conversion rank of U is greater than or equal to the integer conversion rank of S, the operand of type S is converted to U. 2) Otherwise, if S can represent all of the values of U, the operand of type U is converted to S. 3) Otherwise, both operands are converted to the unsigned integer type corresponding to S. (since C++11)(until C++23) 1) If either operand is of scoped enumeration type, no conversions are performed; if the other operand does not have the same type, the expression is ill-formed. 2) Otherwise, if either operand is of floating-point type, the following rules are applied: 1) If both operands have the same type, no further conversion is needed. 2) Otherwise, if one of the operands is of a non-floating-point type, that operand is converted to the type of the other operand. 3) Otherwise, if the floating-point conversion ranks of the types of the operands are ordered but not equal, then the operand of the type with the lesser floating-point conversion rank is converted to the type of the other operand. 4) Otherwise, if the floating-point conversion ranks of the types of the operands are equal, then the operand with the lesser floating-point conversion subrank is converted to the type of the other operand. 5) Otherwise, the expression is ill-formed. 3) Otherwise, integral promotions are performed on both operands. Then the following rules are applied to the promoted operands: 1) If both operands have the same type, no further conversion is needed. 2) Otherwise, if both operands have signed integer types or both have unsigned integer types, the operand with the type of lesser integer conversion rank is converted to the type of the other operand. 3) Otherwise, one operand is of an signed integer type S, the other operand is of an unsigned integer type U. The follwing rules apply: 1) If the integer conversion rank of U is greater than or equal to the integer conversion rank of S, the operand of type S is converted to U. 2) Otherwise, if S can represent all of the values of U, the operand of type U is converted to S. 3) Otherwise, both operands are converted to the unsigned integer type corresponding to S. (since C++23)

 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)

### 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:
• long long
• long
• int
• short
• signed char
• The rank of any unsigned integer type equals the rank of the corresponding signed integer type.
• The rank of any standard integer type is greater than the rank of any extended integer type with the same width.
• The rank of char equals the rank of signed char and unsigned char.
• The rank of bool is less than the rank of all standard integer types.
• The ranks of char8_t, (since C++20)char16_t, char32_t, and wchar_t equal the ranks of their underlying types, which means:
 The rank of char8_t equals the rank of unsigned char. (since C++20)
• The rank of char16_t equals the rank of std::uint_least16_t.
• The rank of char32_t equals the rank of std::uint_least32_t.
• The rank of whcar_t equals the rank of its implementation-defined underlying type.
• The rank of any extended signed integer type relative to another extended signed integer type with the same width is implementation-defined, but still subject to the other rules for determining the integer conversion rank.
• For all integer types T1, T2, and T3, if T1 has greater rank than T2 and T2 has greater rank than T3, then T1 has greater rank than T3.

The integer conversion rank is also used in the definition of integral promotion.

(since C++11)

### Floating-point conversion rank and subrank

#### Floating-point conversion rank

Every floating-point type has a floating-point conversion rank defined as follows:

• The rank of a floating point type T is greater than the rank of any floating-point type whose set of values is a proper subset of the set of values of T.
• The ranks of the following floating-point types decrease in order:
• long double
• double
• float
• Two extended floating-point types with the same set of values have equal ranks.
• An extended floating-point type with the same set of values as exactly one cv-unqualified standard floating-point type has a rank equal to the rank of that standard floating-point type.
• An extended floating-point type with the same set of values as more than one cv-unqualified standard floating-point type has a rank equal to the rank of double.

#### Floating-point conversion subrank

Floating-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 std::float16_t, std::float32_t, std::float64_t, and std::float128_t (fixed width floating-point types) have a greater conversion subrank than any standard floating-point type with equal conversion rank. Otherwise, the conversion subrank order is implementation-defined.

#### Usage

The floating-point conversion rank and subrank are also used to

(since C++23)