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

많은 이항 연산자는 arithmetic 또는 enumeration 타입의 피연산자를 기대하며, 유사한 방식으로 변환을 유발하고 결과 타입을 생성합니다. 목적은 공통 타입을 생성하는 것이며, 이는 결과의 타입이기도 합니다. 이러한 패턴을 usual arithmetic conversions (일반 산술 변환)이라고 합니다.

목차

정의

일반적인 산술 변환은 다음과 같이 정의됩니다:

스테이지 1

두 피연산자에 lvalue-to-rvalue conversion 을 적용하며, 결과로 생성된 prvalue들은 나머지 처리 과정에서 원래 피연산자 대신 사용됩니다.

Stage 2

  • 피연산자 중 하나가 scoped enumeration type 인 경우, 어떠한 변환도 수행되지 않습니다; 다른 피연산자가 동일한 타입을 가지지 않으면, 해당 표현식은 ill-formed입니다.
  • 그렇지 않은 경우, 다음 단계로 진행합니다.
(since C++11)

Stage 3

  • 피연산자 중 하나가 enumeration type 이고 다른 피연산자가 다른 열거형 타입이나 부동소수점 타입인 경우, 해당 표현식은 잘못된 형식입니다.
  • 그렇지 않으면 다음 단계로 진행합니다.
(C++26부터)

단계 4

  • 두 피연산자가 동일한 타입을 가질 경우, 추가 변환은 수행되지 않습니다.
  • 그렇지 않고 피연산자 중 하나가 부동소수점 타입이 아닐 경우, 해당 피연산자는 다른 피연산자의 타입으로 변환됩니다.
  • 그렇지 않고 피연산자 타입들의 floating-point conversion ranks 순서가 지정되어 있지만 (since C++23) 동일하지 않을 경우, 더 낮은 floating-point conversion rank를 가진 타입의 피연산자는 다른 피연산자의 타입으로 변환됩니다.
  • 그렇지 않고 피연산자들의 타입 간 부동소수점 변환 순위가 동일하다면, 더 낮은 부동소수점 변환 하위 순위 를 가진 피연산자가 다른 피연산자의 타입으로 변환됩니다.
  • 그렇지 않으면, 해당 표현식은 잘못된 형식입니다.
(C++23부터)
  • 그렇지 않으면, 두 피연산자가 모두 정수 타입인 경우 다음 단계로 진행합니다.

Stage 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)

정수 변환 순위

모든 integer type 은 다음과 같이 정의된 integer conversion rank 를 가집니다:

  • char signed char (만약 char 가 부호 있는 경우)를 제외한 어떠한 두 부호 있는 정수 타입도 동일한 표현을 가지더라도 동일한 순위를 가지지 않습니다.
  • 부호 있는 정수 타입의 순위는 더 작은 너비를 가진 어떤 부호 있는 정수 타입의 순위보다 큽니다.
  • 다음 정수 타입들의 순위는 아래 순서대로 감소합니다:
  • long long
(C++11부터)
  • long
  • int
  • short
  • signed char
  • 부호 없는 정수형의 순위는 해당 부호 있는 정수형의 순위와 동일합니다.
  • 동일한 너비를 가진 확장 정수 타입보다 표준 정수 타입의 랭크가 더 높습니다.
(since C++11)
  • bool 의 순위는 모든 표준 정수형의 순위보다 낮습니다.
  • 인코딩 문자형( char , char8_t (C++20부터) , char16_t , char32_t , (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-unqualified 표준 부동소수점 타입과 동일한 값 집합을 갖는 확장 부동소수점 타입은 해당 표준 부동소수점 타입과 동일한 랭크를 가집니다.
  • 둘 이상의 cv-unqualified 표준 부동소수점 타입과 동일한 값 집합을 갖는 확장 부동소수점 타입은 double 의 랭크와 동일한 랭크를 가집니다.
(C++23부터)


부동소수점 변환 서브순위

동일한 부동소수점 변환 순위를 가지는 부동소수점 타입들은 부동소수점 변환 서브순위 에 따라 정렬됩니다. 서브순위는 동일한 순위를 가진 타입들 사이에서 완전 순서를 형성합니다.

std::float16_t , std::float32_t , std::float64_t , 및 std::float128_t 타입들( 고정 너비 부동소수점 타입 )은 동일한 변환 순위를 가지는 표준 부동소수점 타입보다 더 높은 변환 서브순위를 가집니다. 그 외의 경우, 변환 서브순위 순서는 구현에 따라 정의됩니다.

(C++23부터)

사용법

부동 소수점 변환 순위와 하위 순위는 또한 다음을 위해 사용됩니다

  • 확장 부동 소수점 타입의 추출에 사용되는 std::num_get::get() 에 의해 추출되는 실제 타입을 결정하고,
  • 확장 부동 소수점 타입의 삽입에 사용되는 std::num_put::put() 에 의해 삽입되는 실제 타입을 결정합니다.
(C++23부터)

결함 보고서

다음 동작 변경 결함 보고서들은 이전에 발표된 C++ 표준에 소급 적용되었습니다.

DR 적용 대상 게시된 동작 올바른 동작
CWG 1642 C++98 일반 산술 변환이 lvalue를 포함할 수 있음 먼저 lvalue-to-rvalue 변환을 적용
CWG 2528 C++20 unsigned char unsigned int 간의 삼중 비교는
중간 정수 승격으로 인해 형식 오류 발생 [1]
피연산자를 실제로 승격시키지 않고
승격된 타입을 기반으로 공통 타입 결정 [2]
CWG 2892 C++98 두 피연산자가 동일한 부동소수점 타입일 때
"더 이상 변환이 필요하지 않음"의 의미가 불명확
"더 이상 변환이 수행되지 않음"으로 변경
  1. 해결 이전에는, unsigned char 가 5단계 시작 시점에 int 로 승격된 후, unsigned int 로 변환됩니다. 그러나 후자의 변환은 축소 변환(narrowing)이므로 삼중 비교(three-way comparison)가 올바르지 않은 형태(ill-formed)가 됩니다.
  2. 해결 이후에도 공통 타입(common type)은 여전히 unsigned int 입니다. 차이점은 unsigned char 가 중간 정수 승격(integral promotion) 없이 직접 unsigned int 로 변환된다는 것입니다. 이 변환은 축소 변환이 아니므로 삼중 비교가 올바른 형태(well-formed)입니다.