名稱空間
變體
操作

常用算術轉換

來自 cppreference.com
< cpp‎ | 語言
 
 
C++ 語言
通用主題
流程控制
條件執行語句
if
迭代語句(迴圈)
跳轉語句
函式
函式宣告
Lambda 函式表示式
inline 說明符
動態異常規範 (直到 C++17*)
noexcept 說明符 (C++11)
異常
名稱空間
型別
說明符
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
儲存期說明符
初始化
 
 

許多期待算術列舉型別運算元的二元運算子,會以類似的方式引發轉換併產生結果型別。其目的是產生一個公共型別,該型別也是結果的型別。此模式被稱為常規算術轉換(usual arithmetic conversions)

目錄

[編輯] 定義

常規算術轉換定義如下

[編輯] 階段 1

對兩個運算元應用左值到右值轉換,在剩餘的過程中使用產生的純右值代替原始運算元。

[編輯] 階段 2

  • 如果任一運算元是有作用域列舉型別,則不執行轉換;如果另一運算元不是相同型別,則表示式非良構。
  • 否則,進入下一階段。
(C++11 起)

[編輯] 階段 3

  • 如果任一運算元是列舉型別,而另一運算元是不同的列舉型別或浮點型別,則表示式非良構。
  • 否則,進入下一階段。
(C++26 起)

[編輯] 階段 4

  • 如果任一運算元是浮點型別,則應用以下規則
  • 如果兩個運算元具有相同的型別,則不會執行進一步的轉換。
  • 否則,如果其中一個運算元是非浮點型別,則該運算元被轉換為另一運算元的型別。
  • 否則,如果運算元型別的浮點轉換等級有序但(C++23 起)不相等,則將浮點轉換等級較低型別的運算元轉換為另一運算元的型別。
  • 否則,如果運算元型別的浮點轉換等級相等,則將浮點轉換次等級較低的運算元轉換為另一運算元的型別。
  • 否則,表示式非良構。
(C++23 起)
  • 否則,兩個運算元都是整數型別,進入下一階段。

[編輯] 階段 5

兩個運算元都被轉換為一個公共型別 C。給定型別 T1T2 作為運算元的提升後型別(根據整數提升規則),應用以下規則來確定 C

  • 如果 T1T2 是相同型別,則 C 就是該型別。
  • 否則,如果 T1T2 都是有符號整數型別或都是無符號整數型別,則 C整數轉換等級更高的型別。
  • 否則,T1T2 中一個型別是有符號整數型別 S,另一個型別是無符號整數型別 U。應用以下規則
  • 如果 U 的整數轉換等級大於或等於 S 的整數轉換等級,則 CU
  • 否則,如果 S 能表示 U 的所有值,則 CS
  • 否則,C 是對應於 S 的無符號整數型別。

如果一個運算元是列舉型別,而另一個運算元是不同的列舉型別或浮點型別,則此行為已被棄用。

(C++20 起)
(直到 C++26)

[編輯] 整數轉換等級

每個整數型別都有一個整數轉換等級(integer conversion rank),定義如下

  • 除了 charsigned char(如果 char 是有符號的),沒有兩個有符號整數型別具有相同的等級,即使它們具有相同的表示。
  • 一個有符號整數型別的等級,大於任何寬度更小的有符號整數型別的等級。
  • 以下整數型別的等級依次降低
  • long long
(C++11 起)
  • long
  • int
  • short
  • signed char
  • 任何無符號整數型別的等級等於其對應的有符號整數型別的等級。
  • 任何標準整數型別的等級,大於任何具有相同寬度的擴充套件整數型別的等級。
(C++11 起)
  • bool 的等級小於所有標準整數型別的等級。
  • 編碼字元型別(char , char8_t(C++20 起), char16_t, char32_t,(C++11 起)wchar_t)的等級等於其底層型別的等級,這意味著
  • char 的等級等於 signed charunsigned char 的等級。
  • char8_t 的等級等於 unsigned char 的等級。
(C++20 起)
(C++11 起)
  • wchar_t 的等級等於其由實現定義的底層型別的等級。
  • 任何擴充套件有符號整數型別相對於另一個具有相同寬度的擴充套件有符號整數型別的等級是由實現定義的,但仍需遵守確定整數轉換等級的其他規則。
(C++11 起)
  • 對於所有整數型別 T1T2T3,如果 T1 的等級高於 T2,且 T2 的等級高於 T3,則 T1 的等級高於 T3

整數轉換等級也用於整數提升的定義中。

[編輯] 浮點轉換等級和次等級

[編輯] 浮點轉換等級

每個浮點型別都有一個浮點轉換等級(floating-point conversion rank),定義如下

  • 標準浮點型別的等級依次降低
    • long double
    • double
    • float
  • 一個浮點型別 T 的等級,大於任何其值集合是 T 的值集合的真子集的浮點型別的等級。
  • 兩個具有相同值集合的擴充套件浮點型別等級相等。
  • 一個其值集合與某個 cv-無限定標準浮點型別完全相同的擴充套件浮點型別,其等級與該標準浮點型別的等級相等。
  • 一個其值集合與多個 cv-無限定標準浮點型別完全相同的擴充套件浮點型別,其等級與 double 的等級相等。
(C++23 起)


浮點轉換次等級

浮點轉換等級相等的浮點型別,透過浮點轉換次等級(floating-point conversion subrank)來排序。次等級在等級相等的型別之間構成一個全序關係。

型別 std::float16_tstd::float32_tstd::float64_tstd::float128_t固定寬度浮點型別)的轉換次等級高於任何具有相同轉換等級的標準浮點型別。否則,轉換次等級的順序是由實現定義的。

(C++23 起)

[編輯] 用法

浮點轉換等級和次等級也用於

(C++23 起)

[編輯] 缺陷報告

下列更改行為的缺陷報告追溯地應用於以前出版的 C++ 標準。

缺陷報告 應用於 釋出時的行為 正確的行為
CWG 1642 C++98 常規算術轉換可能涉及左值 首先應用左值到右值轉換
CWG 2528 C++20 unsigned char
unsigned int 之間的三路比較非良構,因為
存在中間的整數提升[1]
基於提升後的型別確定
公共型別,而不需要
實際提升運算元[2]
CWG 2892 C++98 當兩個運算元都是相同的
浮點型別時,“不需要
進一步轉換”的含義不明確
更改為“不會執行
進一步轉換”
  1. 在解決此問題前,unsigned char 在階段 5 開始時被提升為 int,然後被轉換為 unsigned int。然而,後一個轉換是窄化轉換,這使得三路比較非良構。
  2. 在解決此問題後,公共型別仍然是 unsigned int。不同之處在於 unsigned char 被直接轉換為 unsigned int,而沒有中間的整數提升。該轉換不是窄化轉換,因此三路比較是良構的。