名稱空間
變體
操作

型別

來自 cppreference.com
< cpp‎ | 語言
 
 
C++ 語言
 
 

物件引用函式(包括函式模板特化)和表示式都具有一個稱為**型別**的屬性,該屬性既限制了這些實體允許的操作,又為原本通用的位序列提供了語義含義。

目錄

[編輯] 型別分類

C++ 型別系統包含以下型別

(C++11 起)
  • 型別 bool
  • 字元型別
  • 窄字元型別
  • 普通字元型別:charsigned charunsigned char[1]
  • 型別 char8_t
(C++20 起)
  • 寬字元型別:char16_tchar32_t(C++11 起)wchar_t
  • 有符號整型型別
  • 標準有符號整型型別:signed charshortintlonglong long
  • 擴充套件有符號整型型別(由實現定義);
(C++11 起)
  • 無符號整型型別
  • 標準無符號整型型別:unsigned charunsigned shortunsignedunsigned longunsigned long long
  • 擴充套件無符號整型型別(每個都對應一個擴充套件有符號整型型別,反之亦然);
(C++11 起)
(C++23 起)
  • 到物件型別的左值引用;
  • 到函式型別的左值引用;
  • 到物件型別的右值引用;
  • 到函式型別的右值引用;
(C++11 起)
(C++11 起)
  1. signed charunsigned char 是窄字元型別,但它們不是字元型別。換句話說,窄字元型別的集合不是字元型別集合的子集。

對於除引用和函式之外的每個非 cv 限定型別,型別系統支援該型別的三個額外的cv 限定版本constvolatileconst volatile)。

[編輯] 其他類別

一個*物件型別*(另請參閱 std::is_object)是一個(可能 cv 限定的)型別,它不是函式型別、不是引用型別、也不是(可能 cv 限定的)void

以下型別統稱為*標量型別*(另請參閱 std::is_scalar

(C++11 起)
  • 這些型別的 cv 限定版本

以下型別統稱為*隱式生存期型別*

以下型別統稱為*可平凡複製型別*

以下型別統稱為*標準佈局型別*

(C++11 起)

型別特性層次結構圖

cpp types v3.svg

注意:SVG 影像的元素是可點選的,但您必須首先在新瀏覽器選項卡中開啟該圖

[編輯] 已棄用類別

以下型別統稱為*POD 型別*(另請參閱 std::is_pod

  • 標量型別
  • POD 類
  • 此類型別的陣列
  • 這些型別的 cv 限定版本
(C++20 中已棄用)

以下型別統稱為*平凡型別*(另請參閱 std::is_trivial

  • 標量型別
  • 平凡類型別
  • 此類型別的陣列
  • 這些型別的 cv 限定版本
(C++11 起)
(C++26 中已棄用)

[編輯] 程式定義型別

一個*程式定義的特化*是一個顯式特化部分特化,它不屬於 C++ 標準庫,也不是由實現定義的。

一個*程式定義型別*是以下型別之一

(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 可用於以下情況

(C++17 前)

Type-id 可以在以下情況下進行一些修改後使用

  • 函式的引數列表中(當省略引數名稱時),type-id 使用 decl-specifier-seq 而不是 type-specifier-seq(特別是,允許某些儲存類說明符);
  • 使用者定義轉換函式的名稱中,抽象宣告符不能包含函式或陣列運算子。

[編輯] 詳細型別說明符

詳細型別說明符可用於引用先前宣告的類名(class、struct 或 union)或先前宣告的列舉名,即使該名稱被非型別宣告隱藏。它們也可用於宣告新的類名。

有關詳細資訊,請參閱詳細型別說明符

[編輯] 靜態型別

透過程式編譯時分析得到的表示式的型別稱為表示式的*靜態型別*。靜態型別在程式執行期間不會改變。

[編輯] 動態型別

如果某個glvalue 表示式引用了多型物件,則其最派生物件的型別稱為動態型別。

// 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 表示式,動態型別總是與靜態型別相同。

[編輯] 不完整型別

以下型別是*不完整型別*

  • 型別 void(可能cv限定);
  • 未完整定義的物件型別:

所有其他型別都是完整型別。

以下任何上下文都要求型別 T 是完整型別

(通常,當 T 的大小和佈局必須已知時。)

如果這些情況中的任何一種出現在翻譯單元中,則型別的定義必須出現在同一翻譯單元中。否則,則不是必需的。

不完整定義的物件型別可以完成

  • 類型別(如 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++ 標準。

缺陷報告 應用於 釋出時的行為 正確的行為
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 型別樹