类型
对象、引用、函数(包括函数模板特化)和表达式 具有称为类型的属性,它既限制了允许对这些实体执行的操作,又为否则通用的位序列提供了语义意义。
内容 |
[编辑] 类型分类
C++ 类型系统包含以下类型
- 基本类型(另请参见 std::is_fundamental)
- 类型 void(另请参见 std::is_void);
|
(自 C++11 起) |
- 算术类型(另请参见 std::is_arithmetic)
- 整数类型(包括cv 限定版本,另请参见 std::is_integral,整数类型的同义词是整数类型)
- 类型 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)。
类型根据其属性被分组到不同的类别中
- 对象类型是(可能cv限定的)不是函数类型、引用类型或可能cv限定的 void 的类型(参见 std::is_object);
- 标量类型 是(可能cv限定的)不是数组类型或类类型的对象类型(参见 std::is_scalar);
- 平凡类型(参见 std::is_trivial),POD 类型(参见 std::is_pod),字面量类型(参见 std::is_literal_type)以及类型特征库或作为命名类型需求中列出的其他类别。
构造一个完整的对象类型,使得其对象表示形式中的字节数不能在类型 std::size_t(即 sizeof
运算符的结果类型)中表示,是非法的。
[edit] 程序定义类型
程序定义的特殊化 是一个 显式特殊化 或 偏特化,它不是 C++ 标准库 的一部分,也不是由实现定义的。
程序定义类型 是以下类型之一
|
(自 C++11 起) |
- 程序定义的特殊化的 实例化。
[edit] 类型命名
可以通过以下方式声明一个名称 来引用一个类型
在 C++ 程序中,通常需要引用没有名称的类型;这样做的语法称为 类型标识符。命名类型 T
的类型标识符的语法与声明类型为 T
的变量或函数的语法完全相同,只是省略了标识符,除了声明语法的 声明说明符序列 被限制为 类型说明符序列 以外,并且只有当类型标识符出现在非模板类型别名声明的右侧时,才能定义新的类型。
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
声明语法的 声明符 部分,在去除名称后,被称为 抽象声明符。
类型标识符可以在以下情况下使用
- 在强制转换表达式中指定目标类型;
- 作为 sizeof,alignof,alignas,new 和 typeid 的参数;
- 在 类型别名 声明的右侧;
- 作为 函数 声明的尾随返回类型;
- 作为 模板类型参数 的默认参数;
- 作为 模板类型参数 的模板参数;
|
(直到 C++17) |
类型标识符可以在以下情况下使用,并进行一些修改
- 在 函数 的参数列表中(当省略参数名称时),类型标识符使用 声明说明符序列 而不是 类型说明符序列(特别是,允许使用一些存储类说明符);
- 在 用户定义转换函数 的名称中,抽象声明符不能包含函数或数组运算符。
本节不完整 原因:8.2[dcl.ambig.res] 如果它可以被简洁地概括 |
本节不完整 原因:提及并链接到 decltype 和 auto |
[edit] 详细类型说明符
详细类型说明符可以用来引用之前声明的类名(class、struct 或 union)或之前声明的枚举名,即使该名称被非类型声明隐藏。它们也可以用来声明新的类名。
有关详细信息,请参见 详细类型说明符。
[edit] 静态类型
从程序的编译时分析结果得到的表达式的类型被称为表达式的静态类型。静态类型在程序执行期间不会改变。
[edit] 动态类型
如果某个 左值表达式 引用了一个 多态对象,则其最派生对象的类型被称为动态类型。
// 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
对于右值表达式,动态类型始终与静态类型相同。
[edit] 不完整类型
以下类型是不完整类型
所有其他类型都是完整的。
以下任何上下文都需要类型 T
是完整的
- 定义或调用返回类型为
T
或参数类型为T
的函数; - 定义类型为
T
的对象; - 声明类型为
T
的非静态类数据成员; - new 表达式 用于类型为
T
的对象或元素类型为T
的数组; - 左值到右值转换 应用于类型
T
的左值; - 对类型
T
进行 隐式 或 显式 转换; - 对类型
T*
或T&
进行 标准转换、dynamic_cast 或 static_cast,除了从 空指针常量 或从 指向可能带 cv 限定的 void 的指针 进行转换; - 对类型
T
的表达式应用 类成员访问运算符; - 对类型
T
应用 typeid、sizeof 或 alignof 运算符; - 对指向
T
的指针应用 算术运算符; - 定义具有基类
T
的类; - 将值赋给类型
T
的左值; - 类型
T
、T&
或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++ 标准。
DR | 应用于 | 发布的行为 | 正确行为 |
---|---|---|---|
CWG 328 | C++98 | 不完整类型的类成员不被禁止 如果从未创建过该类类型的对象 |
非静态类数据成员 需要是完整的 |
CWG 977 | C++98 | 枚举类型在其定义中变为 完整的时间点不清楚 |
一旦确定 基础类型,类型就变为完整 |
CWG 1362 | C++98 | 用户定义的转换为类型 T* 或 T& 需要 T 是完整的 |
不需要 |
CWG 1464 | C++98 | 对象大小可能无法在 std::size_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.11 基本类型 [basic.fundamental]
- C++20 标准 (ISO/IEC 14882:2020)
- TBD 基本类型 [basic.fundamental]
- C++17 标准 (ISO/IEC 14882:2017)
- TBD 基本类型 [basic.fundamental]
- C++14 标准 (ISO/IEC 14882:2014)
- TBD 基本类型 [basic.fundamental]
- C++11 标准 (ISO/IEC 14882:2011)
- TBD 基本类型 [basic.fundamental]
- C++98 标准 (ISO/IEC 14882:1998)
- TBD 基本类型 [basic.fundamental]
[编辑] 另请参阅
C 文档 for 类型
|