命名空间
变体
操作

声明

来自 cppreference.cn
< cpp‎ | language
 
 
C++ 语言
通用主题
流控制
条件执行语句
if
迭代语句(循环)
for
范围 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 起)
转型
内存分配
类特有函数属性
虚函数
override 说明符 (C++11 起)  
final 说明符 (C++11 起)
explicit (C++11 起)
static

特殊成员函数
模板
模板特化
形参包 (C++11 起)
其他
 
 

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

声明是下列之一

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

内容

[编辑] 简单声明

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

decl-specifier-seq init-declarator-list (可选) ; (1)
attr decl-specifier-seq init-declarator-list ; (2) (C++11 起)
decl-specifier-seq - 说明符序列
init-declarator-list - 逗号分隔的 init-declarator 列表(见下文)
attr - 任意数量的 属性 序列


仅当声明具名类或具名枚举时,才能省略 init-declarator-list。

结构化绑定声明 也是简单声明。

(C++17 起)


init-declarator 的语法定义如下

声明符 初始化器 (1)
声明符 requires-clause (可选) contract-specs (可选) (2)
1) 带初始化器的声明符。
2) 不带初始化器的声明符。
声明符 - 声明符
初始化器 - 初始化器
requires-clause - (C++20 起) requires 子句
contract-specs - (C++26 起) 函数契约说明符列表


仅当 声明符 声明模板函数时,才能出现 requires-clause。

(C++20 起)

仅当 声明符 声明函数或函数模板时,才能出现 contract-specs。

(C++26 起)

[编辑] 说明符

声明说明符 (decl-specifier-seq) 是以下空白分隔的说明符序列,顺序任意

  • inline 说明符也允许用于变量声明。
(C++17 起)
  • friend 说明符,允许在类和函数声明中使用。
  • constexpr 说明符,仅允许在变量定义、函数和函数模板声明以及字面类型静态数据成员的声明中使用。
(C++11 起)
  • consteval 说明符,仅允许在函数和函数模板声明中使用。
  • constinit 说明符,仅允许在具有静态或线程存储期的变量声明中使用。在 decl-specifier-seq 中,最多允许出现 constexprconstevalconstinit 说明符之一。
(C++20 起)
  • 存储类说明符register(于 C++17 前) staticthread_local(C++11 起) externmutable)。仅允许一个存储类说明符,除非 thread_local 可以与 externstatic 一起出现(C++11 起)
  • 类型说明符 (type-specifier-seq),一个命名类型的说明符序列。声明引入的每个实体的类型都是此类型,可以选择由声明符修改(见下文)。此说明符序列也由 type-id 使用。只有以下说明符是 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 S D1, D2, D3; 都被处理,如同它是具有相同说明符的独立声明:S D1; S D2; S D3;

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

声明符是下列之一

unqualified-id attr (可选) (1)
qualified-id attr (可选) (2)
... 标识符 attr (可选) (3) (C++11 起)
* attr (可选) cv (可选) 声明符 (4)
nested-name-specifier * attr (可选) cv (可选) 声明符 (5)
& attr (可选) 声明符 (6)
&& attr (可选) 声明符 (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 起)

cv 是 const 和 volatile 限定符的序列,其中任一限定符在序列中最多出现一次。

[编辑] 注意

当 block-declaration 出现在块内,并且声明引入的标识符先前在外部块中声明时,外部声明在该块的剩余部分中被隐藏

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

[编辑] 示例

注意:此示例演示了如何根据语言语法解析一些复杂的声明。其他常用的助记方法包括:螺旋法则由内而外阅读声明镜像使用。 还有一个自动解析器,网址为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)>);
}

[编辑] 缺陷报告

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

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

[编辑] 参见

C 文档 关于 声明