類型
物件、參照、函式(包含函式樣板特化)以及表達式都具有一種稱為「類型」(type)的屬性,該屬性不僅限制了這些實體所允許的操作,也為原本僅是通用的位元序列提供了語意意義。
目錄 |
[編輯] 類型分類
C++ 類型系統包含以下類型
- void 類型(參見 std::is_void);
|
(C++11 起) |
- 算術類型(參見 std::is_arithmetic)
- 整數類型(包含 cv 限定版本,參見 std::is_integral,整數類型的同義詞為 integer type)
- bool 類型;
- 字元類型
- 窄字元類型
- 一般字元類型:char, signed char, unsigned char[1]
|
(自 C++20 起) |
- 寬字元類型:char16_t, char32_t, (C++11 起)wchar_t;
- 帶符號整數類型
- 標準帶符號整數類型:signed char, short, int, long, long long;
|
(C++11 起) |
- 無符號整數類型
- 標準無符號整數類型:unsigned char, unsigned short, unsigned, unsigned long, unsigned long long;
|
(C++11 起) |
- 浮點類型(參見 std::is_floating_point)
- 標準浮點類型:float, double, long double 以及它們的 cv 限定版本;
| (自 C++23 起) |
- 複合類型(參見 std::is_compound)
-
-
- 物件類型的左值參照;
- 函式類型的左值參照;
-
|
(C++11 起) |
- 指標類型(參見 std::is_pointer)
- 陣列類型(參見 std::is_array);
- 函式類型(參見 std::is_function);
- 列舉類型(參見 std::is_enum);
| (C++11 起) |
- 類別類型:
- 非聯合體類型(參見 std::is_class);
- 聯合體類型(參見 std::is_union)。
- ↑ signed char 和 unsigned char 是窄字元類型,但它們不是「字元類型」。換句話說,窄字元類型的集合不是字元類型集合的子集。
對於每一種非 cv 限定、且非參照與函式的類型,類型系統支援該類型的三種額外的 cv 限定版本(const、volatile 以及 const volatile)。
[編輯] 其他類別
物件類型(參見 std::is_object)是指一種(可能帶有 cv 限定的)類型,它不是函式類型,不是參照類型,也不是(可能帶有 cv 限定的)void。
下列類型統稱為「純量類型」(scalar types,參見 std::is_scalar):
| (C++11 起) |
- 這些類型的 cv 限定版本
下列類型統稱為「隱式生命週期類型」(implicit-lifetime types):
- 純量類型
- 隱式生命週期類別類型
- 陣列類型
- 這些類型的 cv 限定版本
|
下列類型統稱為「平凡可複製類型」(trivially copyable types):
下列類型統稱為「標準佈局類型」(standard-layout types):
|
(C++11 起) |
| 類型特徵層級圖 |
|---|
|
注意:SVG 影像中的元素皆可點擊,但您必須先在新瀏覽器分頁中開啟該圖表 |
[編輯] 已棄用的類別
|
下列類型統稱為「POD 類型」(參見 std::is_pod):
|
(C++20 中已棄用) |
|
下列類型統稱為「平凡類型」(trivial types,參見 std::is_trivial):
|
(C++11 起) (在 C++26 中棄用) |
[編輯] 程式定義類型
「程式定義特化」(program-defined specialization)是指非 C++ 標準函式庫的一部分,且不由實作所定義的顯式特化或部分特化。
「程式定義類型」(program-defined type)是下列類型之一:
|
(C++11 起) |
- 程式定義特化的具現化。
[編輯] 類型命名
可以透過下列方式宣告一個指向類型的名稱:
C++ 程式中經常需要參照沒有名稱的類型;其語法稱為 type-id。命名類型 T 的 type-id 語法,與宣告類型為 T 的變數或函式的宣告語法完全相同(省略識別符),例外之處在於宣告語法中的 decl-specifier-seq 被限制為 type-specifier-seq,且僅在 type-id 出現在非樣板類型別名宣告的右側時,才允許定義新類型。
int* p; // declaration of a pointer to int static_cast<int*>(p); // type-id is "int*" int a[3]; // declaration of an array of 3 int new int[3]; // type-id is "int[3]" (called new-type-id) int (*(*x[2])())[3]; // declaration of an array of 2 pointers to functions // returning pointer to array of 3 int new (int (*(*[2])())[3]); // type-id is "int (*(*[2])())[3]" void f(int); // declaration of a function taking int and returning void std::function<void(int)> x = f; // type template parameter is a type-id "void(int)" std::function<auto(int) -> void> y = f; // same std::vector<int> v; // declaration of a vector of int sizeof(std::vector<int>); // type-id is "std::vector<int>" struct { int x; } b; // creates a new type and declares an object b of that type sizeof(struct { int x; }); // error: cannot define new types in a sizeof expression using t = struct { int x; }; // creates a new type and declares t as an alias of that type sizeof(static int); // error: storage class specifiers not part of type-specifier-seq std::function<inline void(int)> f; // error: neither are function specifiers
宣告語法中移除名稱後的 declarator(宣告子)部分,稱為 abstract-declarator(抽象宣告子)。
type-id 可用於下列情況:
- 在轉型表達式中指定目標類型;
- 作為
sizeof、alignof、alignas、new以及typeid的引數; - 在類型別名宣告的右側;
- 作為函式宣告的後置返回類型;
- 作為樣板類型參數的預設引數;
- 作為樣板類型參數的樣板引數;
|
(直到 C++17) |
type-id 在某些修改後,可用於下列情況:
- 在函式的參數列表中(當省略參數名稱時),type-id 使用 decl-specifier-seq 而非 type-specifier-seq(特別是允許某些儲存類別說明符);
- 在使用者自訂轉換函式的名稱中,抽象宣告子不能包含函式或陣列運算子。
| 本節尚不完整 原因:8.2[dcl.ambig.res] 如果可以精簡總結 |
| 本節尚不完整 原因:提及並連結至 decltype 和 auto |
[編輯] 詳述類型說明符 (Elaborated type specifier)
詳述類型說明符可用於參照先前宣告的類別名稱(class, struct 或 union)或先前宣告的列舉名稱,即使該名稱已被非類型宣告所隱藏。它們也可用於宣告新的類別名稱。
詳細資訊請參見詳述類型說明符。
[編輯] 靜態類型
由編譯時期程式分析所得出的表達式類型,稱為該表達式的「靜態類型」。靜態類型在程式執行期間不會改變。
[編輯] 動態類型
如果某個泛左值表達式參照到一個多型物件,則其「最衍生物件」(most derived object)的類型稱為動態類型。
// given struct B { virtual ~B() {} }; // polymorphic type struct D : B {}; // polymorphic type D d; // most-derived object B* ptr = &d; // the static type of (*ptr) is B // the dynamic type of (*ptr) is D
對於純右值 (prvalue) 表達式,其動態類型永遠與靜態類型相同。
[編輯] 不完整類型
下列類型屬於「不完整類型」(incomplete types):
- void 類型(可能帶有 cv 限定);
- 未完整定義的物件類型:
所有其他類型皆為完整類型。
下列任一情境都要求類型 T 必須是完整的:
- 返回類型為
T或參數類型為T的函式的定義或呼叫; - 類型
T物件的定義; - 類型
T的非靜態類別資料成員的宣告; - 針對
T類型物件或元素類型為T的陣列的new表達式; - 應用於類型
T之泛左值的左值轉右值轉換; - 轉換至
T類型的隱式或顯式轉換; - 轉換至 T* 或 T& 的標準轉換、
dynamic_cast或static_cast,但從空指標常數或指向可能帶 cv 限定之 void 的指標轉換時除外; - 應用於
T類型表達式的類別成員存取運算子; - 應用於
T類型的typeid、sizeof或alignof運算子; - 應用於指向
T之指標的算術運算子; - 以
T為基底類別的類別定義; - 賦值給
T類型的左值; - 類型為
T、T& 或 T* 的處理器 (handler)。
(通常在必須已知 T 的大小與佈局時。)
如果這些情況中的任何一個出現在轉譯單元 (translation unit) 中,則該類型的定義必須出現在同一個轉譯單元中。否則,則無此要求。
未完整定義的物件類型可以被完成:
- 類別類型(如 class X)在轉譯單元的某處可能被視為不完整的,而稍後被視為完整的;類型 class X 在這兩處是相同的類型。
struct X; // declaration of X, no definition provided yet extern X* xp; // xp is a pointer to an incomplete type: // the definition of X is not reachable void foo() { xp++; // ill-formed: X is incomplete } struct X { int i; }; // definition of X X x; // OK: the definition of X is reachable void bar() { xp = &x; // OK: type is “pointer to X” xp++; // OK: X is complete }
- 陣列物件的宣告類型可能是「不完整類別類型的陣列」,因此是不完整的;如果該類別類型稍後在轉譯單元中被完成,則陣列類型也會變為完整;這兩處的陣列類型是相同的類型。
- 陣列物件的宣告類型可能是「未知邊界的陣列」,因此在轉譯單元的某處是不完整的,而稍後變為完整;這兩處的陣列類型(「
T之未知邊界的陣列」與「N個T的陣列」)是不同的類型。
指向未知邊界陣列的指標或參照類型,永久地指向或參照一個不完整類型。由 typedef 宣告所命名的未知邊界陣列,永久地參照一個不完整類型。在上述兩種情況下,陣列類型都無法被完成。
extern int arr[]; // the type of arr is incomplete typedef int UNKA[]; // UNKA is an incomplete type UNKA* arrp; // arrp is a pointer to an incomplete type UNKA** arrpp; void foo() { arrp++; // error: UNKA is an incomplete type arrpp++; // OK: sizeof UNKA* is known } int arr[10]; // now the type of arr is complete void bar() { arrp = &arr; // OK: qualification conversion (since C++20) arrp++; // error: UNKA cannot be completed }
[編輯] 缺陷報告
下列更改行為的缺陷報告追溯應用於之前的 C++ 標準。
| DR | 應用於 | 出版時的行為 | 正確的行為 |
|---|---|---|---|
| CWG 328 | C++98 | 不完整類型的類別成員未被禁止 如果該類別類型的物件從未被建立 |
非靜態類別資料成員 需要是完整的 |
| CWG 977 | C++98 | 列舉類型變為 完整的時間點在其定義中是不明確的 |
一旦其 底層類型被確定,該類型即為完整的 |
| CWG 1362 | C++98 | 轉換至 T* 或 T& 的使用者自訂轉換要求 T 為完整類型 |
不再需要 |
| CWG 2006 | C++98 | cv 限定的 void 類型曾經是物件類型與完整類型 | 從這兩個類別中排除 |
| CWG 2448 | C++98 | 僅有非 cv 限定類型可以是整數與浮點類型 | 允許 cv 限定類型 |
| CWG 2630 | C++98 | 類別在該類別定義出現的轉譯單元之外是否被視為完整 是不明確的 |
如果類別的定義 在此情況下是可及的, 則該類別是完整的 |
| CWG 2643 | C++98 | 指向未知邊界陣列的指標類型 無法被完成(但它已經是完整的) |
所指向的陣列類型 無法被完成 |
| LWG 2139 | C++98 | “使用者自訂類型”的意義不明確 | 改為定義並使用 “程式 定義類型” |
| LWG 3119 | C++11 | 閉包類型是否為程式定義類型是不明確的 | 現已明確化 |
[編輯] 參考
- C++23 標準 (ISO/IEC 14882:2024)
- 6.8.2 基礎類型 [basic.fundamental]
- C++20 標準 (ISO/IEC 14882:2020)
- 6.8.2 基礎類型 [basic.fundamental]
- C++17 標準 (ISO/IEC 14882:2017)
- 6.9.1 基礎類型 [basic.fundamental]
- C++14 標準 (ISO/IEC 14882:2014)
- 3.9.1 基礎類型 [basic.fundamental]
- C++11 標準 (ISO/IEC 14882:2011)
- 3.9.1 基礎類型 [basic.fundamental]
- C++98 標準 (ISO/IEC 14882:1998)
- 3.9.1 基礎類型 [basic.fundamental]
[編輯] 參見
| 型別特徵 | 一種基於樣板的編譯時期介面,用於查詢類型的屬性 |
| C 文件 關於 類型 (Type)
| |
[編輯] 外部連結
| 1. | Howard Hinnant 的 C++0x 類型樹 |