命名空间
变体
操作

类型

来自 cppreference.com
< cpp‎ | language
 
 
C++ 语言
一般主题
流程控制
条件执行语句
if
迭代语句(循环)
for
range-for (C++11)
跳转语句
函数
函数声明
Lambda 函数表达式
inline 说明符
动态异常规范 (直到 C++17*)
noexcept 说明符 (C++11)
异常
命名空间
类型
说明符
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
存储持续时间说明符
初始化
表达式
替代表示
字面量
布尔值 - 整数 - 浮点数
字符 - 字符串 - nullptr (C++11)
用户定义的 (C++11)
实用程序
属性 (C++11)
类型
typedef 声明
类型别名声明 (C++11)
强制转换
内存分配
特定于类的函数属性
explicit (C++11)
static

特殊成员函数
模板
其他
 
 

对象引用函数(包括函数模板特化)和表达式 具有称为类型的属性,它既限制了允许对这些实体执行的操作,又为否则通用的位序列提供了语义意义。

内容

[编辑] 类型分类

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::size_t(即 sizeof 运算符的结果类型)中表示,是非法的。

cpp types.svg

[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

声明语法的 声明符 部分,在去除名称后,被称为 抽象声明符

类型标识符可以在以下情况下使用

(直到 C++17)

类型标识符可以在以下情况下使用,并进行一些修改

  • 函数 的参数列表中(当省略参数名称时),类型标识符使用 声明说明符序列 而不是 类型说明符序列(特别是,允许使用一些存储类说明符);
  • 用户定义转换函数 的名称中,抽象声明符不能包含函数或数组运算符。

[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] 不完整类型

以下类型是不完整类型

  • 类型 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++ 标准。

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 类型