命名空间
变体
操作

声明

来自 cppreference.com
< cpp‎ | 语言
 
 
C++ 语言
 
 

声明 是将名称引入(或重新引入) C++ 程序的方式。并非所有声明都真正声明任何内容,并且每种类型的实体的声明方式都不同。定义 是足以使用由名称标识的实体的声明。

声明是以下之一

  • 属性声明(attr ;)
(自 C++11)
  • 空声明(;)
  • 没有 decl-specifier-seq  的函数声明
attr (可选) declarator ;
attr - (自 C++11) 任意数量的 属性 序列
declarator - 函数声明符
此声明必须声明一个构造函数、析构函数或用户定义的类型 转换函数。它只能用作 模板声明显式特化 或显式实例化的一部分。
  • block-declaration(可以在 内出现的声明),它反过来可以是以下之一
(自 C++11)
(自 C++20)
(自 C++11)
  • 简单声明

内容

[编辑] 简单声明

简单声明是一个语句,它引入、创建并可选地初始化一个或多个标识符,通常是变量。

decl-specifier-seq init-declarator-list (可选) ; (1)
attr decl-specifier-seq init-declarator-list; (2)
attr - (自 C++11) 任意数量的 属性 序列
decl-specifier-seq - 说明符 序列(见下文)
init-declarator-list - 用逗号分隔的声明符列表,并带可选的初始化器。当声明命名类/结构体/联合体或命名枚举时,init-declarator-list 是可选的

一个结构化绑定声明 也是一个简单声明。 (自 C++17 起)

[编辑] 说明符

声明说明符 (decl-specifier-seq) 是以下空格分隔的说明符的序列,可以按任何顺序排列

  • the inline 说明符也允许用于变量声明。
(自 C++17 起)
  • the friend 说明符,允许在类和函数声明中使用。
  • the constexpr 说明符,只允许在变量定义、函数和函数模板声明中使用,以及在文字类型静态数据成员的声明中使用。
(自 C++11)
  • the consteval 说明符,只允许在函数和函数模板声明中使用。
  • the constinit 说明符,只允许在具有静态或线程存储期的变量声明中使用。最多允许一个constexprconstevalconstinit 说明符出现在 decl-specifier-seq 中。
(自 C++20)
  • 存储类说明符 (register, (直至 C++17) static, thread_local, (自 C++11 起) extern, mutable)。只允许一个存储类说明符,但 thread_local 可以与 externstatic 同时出现 (自 C++11 起)
  • 类型说明符 (type-specifier-seq),一个命名类型的说明符序列。声明引入的每个实体的类型都是此类型,可以选择由声明符(见下文)进行修改。此说明符序列也由类型标识符 使用。以下说明符是 type-specifier-seq 的一部分,可以按任何顺序排列
(自 C++11)
(自 C++26 起)
(自 C++17 起)
在 decl-specifier-seq 中只允许一个类型说明符,但以下情况除外
  • const 可以与除自身以外的任何类型说明符结合使用。
  • volatile 可以与除自身以外的任何类型说明符结合使用。
  • signedunsigned 可以与 charlongshortint 结合使用。
  • shortlong 可以与 int 结合使用。
  • long 可以与 double 结合使用。
  • long 可以与 long 结合使用。
(自 C++11)

属性 可以出现在 decl-specifier-seq 中,在这种情况下,它们将应用于先前说明符确定的类型。

decl-specifier-seq 中重复任何说明符,例如 const static constvirtual inline virtual 是错误的,但 long 可以出现两次 (自 C++11 起)

[编辑] 声明符

init-declarator-list 是一个或多个 init-declarator 的逗号分隔序列,它们的语法如下

declarator initializer (可选) (1)
declarator requires-clause (2) (自 C++20)
declarator - 声明符
初始化器 - 可选的初始化器(除非强制要求,例如在初始化引用或常量对象时)。有关详细信息,请参见初始化
requires-clause - requires-clause,它向函数声明 添加一个约束

init-declarator 序列中的每个 init-declarator S D1, D2, D3; 都会被处理,就好像它是一个具有相同说明符的独立声明一样:S D1; S D2; S D3;

每个声明符都引入一个确切的对象、引用、函数或(对于 typedef 声明)类型别名,其类型由 decl-specifier-seq 提供,并可以选择由声明符中的运算符进行修改,例如 &(引用)或 [](数组)或 ()(函数返回)。这些运算符可以递归地应用,如下所示。

一个 declarator 是以下内容之一

unqualified-id attr (可选) (1)
qualified-id attr (可选) (2)
... identifier attr (可选) (3) (自 C++11)
* attr (可选) cv (可选) declarator (4)
nested-name-specifier * attr (可选) cv (可选) declarator (5)
& attr (可选) declarator (6)
&& attr (可选) declarator (7) (自 C++11)
noptr-declarator [ constexpr (可选) ] attr (可选) (8)
noptr-declarator ( parameter-list ) cv (可选) ref  (可选) except (可选) attr (可选) (9)
1) 声明的名称
2) 使用限定标识符 (qualified-id) 的声明符将定义或重新声明先前声明的命名空间成员类成员
3) 参数包,只出现在参数声明 中。
4) 指针声明符:声明 S * D;D 声明为指向由 decl-specifier-seq S 确定的类型的指针。
5) 成员指针声明: 声明 S C::* D;D 声明为指向 C 的成员的指针,其类型由 decl-specifier-seq S 确定。 nested-name-specifier 是一个 名称和作用域解析运算符 :: 的序列
6) 左值引用声明符: 声明 S & D;D 声明为对由 decl-specifier-seq S 确定的类型的左值引用。
7) 右值引用声明符: 声明 S && D;D 声明为对由 decl-specifier-seq S 确定的类型的右值引用。
8) 数组声明符noptr-declarator 是任何有效的声明符,但如果它以 *、& 或 && 开头,则必须用括号括起来。
9) 函数声明符noptr-declarator 是任何有效的声明符,但如果它以 *、& 或 && 开头,则必须用括号括起来。 它可能以可选的尾随返回类型结束。(自 C++11 起)

在所有情况下,attr 都是 属性 的可选序列。当它出现在标识符之后时,它应用于被声明的对象。

(自 C++11)

cvconst 和 volatile 限定符的序列,其中每个限定符最多可以在序列中出现一次。

[edit] 注释

block-declaration 出现在 块内 时,如果由声明引入的标识符之前已在外部块中声明,则 外部声明将被隐藏,直到块的其余部分。

如果声明引入了一个具有自动存储期的变量,则在执行其声明语句时初始化它。在一个块中声明的所有自动变量在退出块时被销毁(无论块是如何退出的:通过 异常goto,或者到达其末尾),按其初始化顺序的相反顺序进行。

[edit] 示例

注意:此示例演示了一些复杂声明是如何根据语言语法解析的。其他常用的助记符是:螺旋规则,从 内向外 阅读,以及 声明镜像使用。 还有一个自动化解析器位于 https://cdecl.org

#include <type_traits>
 
struct S
{
    int member;
    // decl-specifier-seq is "int"
    // declarator is "member"
} obj, *pObj(&obj);
// decl-specifier-seq is "struct S { int member; }"
// declarator "obj" declares an object of type S
// declarator "*pObj" declares a pointer to S,
//     and initializer "(&obj)" initializes it
 
int i = 1, *p = nullptr, f(), (*pf)(double);
// decl-specifier-seq is "int"
// declarator "i" declares a variable of type int,
//     and initializer "= 1" initializes it
// declarator "*p" declares a variable of type int*,
//     and initializer "= nullptr" initializes it
// declarator "f()" declares (but doesn't define)
//     a function taking no arguments and returning int
// declarator "(*pf)(double)" declares a pointer to function
//     taking double and returning int
 
int (*(*var1)(double))[3] = nullptr;
// decl-specifier-seq is "int"
// declarator is "(*(*var1)(double))[3]"
// initializer is "= nullptr"
 
// 1. declarator "(*(*var1)(double))[3]" is an array declarator:
//    Type declared is: "(*(*var1)(double))" array of 3 elements
// 2. declarator "(*(*var1)(double))" is a pointer declarator:
//    Type declared is: "(*var1)(double)" pointer to array of 3 elements
// 3. declarator "(*var1)(double)" is a function declarator:
//    Type declared is: "(*var1)" function taking "(double)",
//    returning pointer to array of 3 elements.
// 4. declarator "(*var1)" is a pointer declarator:
//    Type declared is: "var1" pointer to function taking "(double)",
//    returning pointer to array of 3 elements.
// 5. declarator "var1" is an identifier.
// This declaration declares the object var1 of type "pointer to function
// taking double and returning pointer to array of 3 elements of type int"
// The initializer "= nullptr" provides the initial value of this pointer.
 
// C++11 alternative syntax:
auto (*var2)(double) -> int (*)[3] = nullptr;
// decl-specifier-seq is "auto"
// declarator is "(*var2)(double) -> int (*)[3]"
// initializer is "= nullptr"
 
// 1. declarator "(*var2)(double) -> int (*)[3]" is a function declarator:
//    Type declared is: "(*var2)" function taking "(double)", returning "int (*)[3]"
// ...
 
int main()
{
    static_assert(std::is_same_v<decltype(var1), decltype(var2)>);
}

[edit] 缺陷报告

以下行为变更缺陷报告已追溯应用于先前发布的 C++ 标准。

DR 应用于 已发布的行为 正确的行为
CWG 482 C++98 重新声明的声明符不能被限定 允许限定声明符
CWG 569 C++98 单个独立的分号不是有效的声明 这是一个空声明,
它没有效果
CWG 1830 C++98 decl-specifier-seq 中允许重复函数说明符 禁止重复

[edit] 另见

C 文档 用于 声明