命名空间
变体
操作

类型

来自 cppreference.cn
< 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 类型树