声明
声明将名字引入(或再引入)到 C++ 程序中。每种实体的声明方式都不同。定义是足以使该名字所标识的实体被使用的声明。
声明是下列之一:
属性(可选) 声明符 ;
|
|||||||||
属性 | - | (C++11 起) 任意数量属性的序列 |
声明符 | - | 函数声明符。 |
- 块声明(能在块中出现的声明),它可以是下列之一:
- 汇编声明
- 类型别名声明 (C++11 起)
- 命名空间别名定义
- using 声明
- using 指令
- using enum 声明 (C++20 起)
- static_assert 声明 (C++11 起)
- 不可见 enum 声明 (C++11 起)
- 简单声明
简单声明
简单声明是引入、创建并可选地初始化一个或数个标识符(典型地为变量)的语句。
声明说明符序列 初始化声明符列表(可选) ;
|
(1) | ||||||||
属性 声明说明符序列 初始化声明符列表;
|
(2) | ||||||||
属性 | - | (C++11 起) 任何数量属性的序列 |
声明说明符序列 (decl-specifier-seq) |
- | 说明符(specifier)的序列(见下文) |
初始化声明符列表 (init-declarator-list) |
- | 带可选的初始化器(initializer)的声明符(declarator)的逗号分隔列表。 初始化声明符列表 在声明具名的 class/struct/union 或具名枚举时是可选的 |
结构化绑定声明也是简单声明。 (C++17 起)
说明符
声明说明符(声明说明符序列)是下列以空白分隔的说明符的序列,顺序不限:
-
typedef
说明符。如果存在,则整个声明是 typedef 声明,且每个声明符引入一个新的类型名,而非对象或函数。 - 函数说明符(
inline
、virtual
、explicit
),仅在函数声明中可以使用。
|
(C++17 起) |
-
friend
说明符,可以在类和函数声明中使用。
|
(C++11 起) |
(C++20 起) |
- 存储类说明符(register、 (C++17 前) static、thread_local (C++11 起)、extern、mutable)。只能使用一个存储类说明符,但
thread_local
可以与extern
或static
一同出现。 - 类型说明符(类型说明符序列),指名一个类型的说明符的序列。声明所引入的每个实体均为此类型,并可以被声明符修饰(见下文)。这个说明符序列也用于类型标识(type-id)。只有下列说明符是 类型说明符序列 的一部分,顺序不限:
(C++11 起) |
(C++17 起) |
-
- 每个 声明说明符序列 中只允许一个类型说明符,但有以下例外:
- -
const
能与自身外的任何类型说明符组合。 - -
volatile
能与自身外的任何类型说明符组合。 - -
signed
或unsigned
能与char
、long
、short
或int
组合。 - -
short
或long
能与int
组合。 - -
long
能与double
组合。
|
(C++11 起) |
属性可以在 声明说明符序列 中出现,此时它们应用于其之前的说明符所确定的类型。
声明说明符序列 中仅有的允许两次出现的说明符是 |
(C++17 起) |
声明符
初始化声明符列表 是一或多个 初始化声明符 的逗号分隔列表,它拥有下列语法:
声明符 初始化器(可选) | (1) | ||||||||
声明符 requires-子句 | (2) | (C++20 起) | |||||||
声明符 | - | 声明符 |
初始化器 | - | 可选的初始化器(除非在必要的场合,例如初始化引用或 const 对象时)。细节见初始化。 |
requires-子句 | - | requires 子句,向函数声明添加制约 |
初始化声明符序列 S D1, D2, D3; 中的每个 初始化声明符,均按照如同它是拥有相同说明符的孤立声明来处理:S D1; S D2; S D3;。
每个声明符恰好引入一个对象、引用、函数或(对于 typedef 声明)类型别名,其类型由 声明说明符序列 提供,并可选地被声明符中的运算符,如 &(~的引用)或 [](~的数组)或 ()(返回~的函数)所修饰。可以递归应用这些声明符,如下所示。
声明符 是下列之一:
无限定标识 属性(可选) | (1) | ||||||||
有限定标识 属性(可选) | (2) | ||||||||
... 标识符 属性(可选)
|
(3) | (C++11 起) | |||||||
* 属性(可选) 限定符(可选) 声明符
|
(4) | ||||||||
嵌套名说明符 * 属性(可选) 限定符(可选) 声明符
|
(5) | ||||||||
& 属性(可选) 声明符
|
(6) | ||||||||
&& 属性(可选) 声明符
|
(7) | (C++11 起) | |||||||
非指针声明符 [ 常量表达式(可选) ] 属性(可选)
|
(8) | ||||||||
非指针声明符 ( 形参列表 ) cv限定符(可选) 引用限定符(可选) 异常说明(可选) 属性(可选)
|
(9) | ||||||||
所有情况下,属性 均为可选的属性的序列。当其紧跟标识符之后出现时,它应用于所声明的对象。 |
(C++11 起) |
限定符 是 const 与 volatile 限定符的序列,其中任一限定符在序列中至多出现一次。
本节未完成 原因:解释名字隐藏规则;变量/函数声明如何隐藏同名的类(而非 typedef) |
注解
块声明出现在代码块内,而当声明中引入的标识符之前已在某个外层代码块中声明时,该代码块的剩余部分中外层声明被隐藏。
如果一个声明引入了一个具有自动存储期的变量,则它在执行其声明语句时被初始化。退出代码块时,所有在该块中声明的自动变量被以其初始化顺序的相反顺序销毁(与如何退出代码块无关:通过异常、goto 或抵达其结尾)。
示例
class C { std::string member; // 声明说明符序列 是 "std::string" // 声明符 是 "member" } obj, *pObj(&obj); // 声明说明符序列为 "class C { std::string member; }" // 声明符 "obj" 定义 C 类型的对象 // 声明符 "*pObj(&obj)" 声明并初始化指向 C 的指针 int a = 1, *p = nullptr, f(), (*pf)(double); // 声明说明符序列为 int // 声明符 a=1 定义并初始化 int 类型的变量 // 声明符 *p=nullptr 定义并初始化 int* 类型的变量 // 声明符 (f)() 声明(但不定义)不接收参数并返回 int 的函数 // 声明符 (*pf)(double) 定义一个指向接收 double 并返回 int 的函数的指针 int (*(*foo)(double))[3] = nullptr; // 声明说明符序列为 int // 1. 声明符 "(*(*foo)(double))[3]" 是数组声明符; // 所声明类型是“含有 3 个 int 元素的数组 /嵌套声明符/ ” // 2. 嵌套声明符是 "(*(*foo)(double))",它是指针声明符 // 所声明类型是“指向【含有 3 个 int 元素的数组】的指针 /嵌套声明符/” // 3. 嵌套声明符是 "(*foo)(double)",它是函数声明符 // 所声明类型是“以【指向含有 3 个 int 元素的数组的指针】 // 为返回值的接受一个 double 参数的函数 /嵌套声明符/” // 4. 嵌套声明符是 "(*foo)",它是(带括号,如函数声明符语法所要求的)指针声明符。 // 所声明类型是“指向【以指向含有 3 个 int 元素的数组的指针 // 为返回值的接受一个 double 参数的函数】的指针 /嵌套声明符/” // 5. 嵌套声明符是 "foo",它是标识符。 // 该声明声明了对象 foo,它的类型是“指向以指向含有 3 个 int 元素的数组的指针 // 为返回值的接受一个 double 参数的函数的指针” // 初始化器 "= nullptr" 提供此指针的初值。