Namespaces
Variants

Type

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

对象 引用 函数 (包括 函数模板特化 )以及 表达式 都具有名为 类型 的属性,该属性既限制了这些实体允许执行的操作,又为原本通用的比特序列提供了语义含义。

目录

类型分类

C++ 类型系统包含以下类型:

(since C++11)
  • 类型 bool
  • 字符类型:
  • 窄字符类型:
  • 普通字符类型: char signed char unsigned char [1]
  • 类型 char8_t
(since C++20)
  • 宽字符类型: char16_t , char32_t , (since C++11) wchar_t
  • 有符号整数类型:
  • 标准有符号整数类型: signed char , short , int , long , long long
  • 扩展的有符号整数类型(由实现定义);
(since C++11)
  • 无符号整数类型:
  • 标准无符号整数类型: unsigned char unsigned short unsigned unsigned long unsigned long long
  • 扩展无符号整数类型(每种类型对应一个扩展有符号整数类型,反之亦然);
(since C++11)
  • 标准浮点类型: float double long double 及其 cv限定版本
(since C++23)
  • 指向对象类型的左值引用;
  • 指向函数类型的左值引用;
  • 对象类型的右值引用;
  • 函数类型的右值引用;
(since C++11)
(自 C++11 起)
  1. signed char unsigned char 是窄字符类型,但它们不是字符类型。换言之,窄字符类型的集合并非字符类型集合的子集。

对于每个非引用类型及函数类型之外的非cv限定类型,类型系统支持该类型的三种附加 cv限定版本 const volatile 以及 const 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 ):

(C++11起)
(C++26起弃用)

程序定义类型

一个 程序定义特化 是指不属于C++ 标准库 且不由实现定义的 显式特化 偏特化

一个 程序定义类型 是以下类型之一:

(since C++11)

类型命名

可以通过以下方式声明 名称 以引用类型:

在C++程序中经常需要引用没有名称的类型;这种语法被称为 类型标识符 。命名类型 T 的类型标识符语法,与声明 T 类型变量或函数的语法完全一致,只是省略了标识符。但存在以下区别:声明语法中的 声明说明符序列 被限制为 类型说明符序列 ,且仅当类型标识符出现在非模板类型别名声明的右侧时,才可以定义新类型。

int* p;               // 声明一个指向 int 的指针
static_cast<int*>(p); // 类型标识为 "int*"
int a[3];   // 声明一个包含 3 个 int 的数组
new int[3]; // 类型标识为 "int[3]"(称为 new-type-id)
int (*(*x[2])())[3];      // 声明一个包含 2 个指向函数的指针的数组
                          // 这些函数返回指向包含 3 个 int 的数组的指针
new (int (*(*[2])())[3]); // 类型标识为 "int (*(*[2])())[3]"
void f(int);                    // 声明一个接受 int 并返回 void 的函数
std::function<void(int)> x = f; // 类型模板参数是一个类型标识 "void(int)"
std::function<auto(int) -> void> y = f; // 同上
std::vector<int> v;       // 声明一个 int 类型的 vector
sizeof(std::vector<int>); // 类型标识为 "std::vector<int>"
struct { int x; } b;         // 创建一个新类型并声明该类型的对象 b
sizeof(struct { int x; });   // 错误:不能在 sizeof 表达式中定义新类型
using t = struct { int x; }; // 创建一个新类型并声明 t 作为该类型的别名
sizeof(static int); // 错误:存储类说明符不是类型说明符序列的一部分
std::function<inline void(int)> f; // 错误:函数说明符也不允许

声明语法中去掉名称的 声明符 部分被称为 抽象声明符

类型标识符可在以下情形中使用:

(直至 C++17)

类型标识符可在以下经过修改的情况下使用:

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

详细类型说明符

详细类型说明符可用于引用先前声明的类名(class、struct 或 union)或先前声明的枚举名,即使该名称 被非类型声明隐藏 。它们也可用于声明新的类名。

请参阅 详细类型说明符 了解详情。

静态类型

通过程序编译时分析得到的表达式类型称为该表达式的 静态类型 。静态类型在程序执行期间不会改变。

动态类型

如果某个 泛左值表达式 引用的是 多态对象 ,则其最终派生对象的类型被称为动态类型。

// 已知条件
struct B { virtual ~B() {} }; // 多态类型
struct D : B {};               // 多态类型
D d; // 最终派生对象
B* ptr = &d;
// (*ptr) 的静态类型是 B
// (*ptr) 的动态类型是 D

对于纯右值表达式,动态类型始终与静态类型相同。

不完整类型

以下类型属于 不完整类型

所有其他类型都是完整的。

以下任意上下文均要求类型 T 为完整类型:

(通常,当需要知道 T 的大小和布局时。)

若翻译单元中出现以下任一情况,则该类型的定义必须出现在同一翻译单元中。否则无需提供定义。

不完整定义的对象类型可以被补全:

  • 类类型(例如 class X )在翻译单元的某个时间点可能被视为不完整类型,而在稍后时间点被视为完整类型;类型 class X 在这两个时间点都是同一类型:
struct X;            // X的声明,尚未提供定义
extern X* xp;        // xp是指向不完整类型的指针:
                     // X的定义不可访问
void foo()
{
    xp++;            // 格式错误:X是不完整类型
}
struct X { int i; }; // X的定义
X x;                 // 正确:X的定义可访问
void bar()
{
    xp = &x;         // 正确:类型为“指向X的指针”
    xp++;            // 正确:X是完整类型
}
  • 数组对象的声明类型可能是一个不完整类类型的数组,因此是不完整的;如果该类型在翻译单元后续被完整定义,则该数组类型变为完整类型;这两个时间点的数组类型是同一类型。
  • 数组对象的声明类型可能是一个未知边界的数组,因此在翻译单元的某个时间点是不完整的,而在后续变为完整;这两个时间点的数组类型("未知边界的 T 数组"和" N T 的数组")是不同的类型。

指向未知边界数组的指针或引用类型永久指向或引用不完整类型。通过 typedef 声明命名的未知边界数组永久引用不完整类型。在这两种情况下,该数组类型均无法被补全:

extern int arr[];   // arr的类型是不完整的
typedef int UNKA[]; // UNKA是不完整类型
UNKA* arrp;         // arrp是指向不完整类型的指针
UNKA** arrpp;
void foo()
{
    arrp++;         // 错误:UNKA是不完整类型
    arrpp++;        // 正确:UNKA*的大小已知
}
int arr[10];        // 现在arr的类型是完整的
void bar()
{
    arrp = &arr;    // 正确:限定转换(自C++20起)
    arrp++;         // 错误:UNKA无法被补全
}

缺陷报告

以下行为变更缺陷报告被追溯应用于先前发布的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]

参见

Type traits 基于模板的编译时接口,用于查询类型的属性
C 文档 关于 Type

外部链接

1. Howard Hinnant的C++0x类型树