外部变量声明是否也声明了一个(对象)实体?

Does an extern variable declaration also declare an (object) entity?

(以下所有标准参考文献均引用 N4659: March 2017 post-Kona working draft/C++17 DIS在标准引文中强调我的)


背景

我正在尝试回答下面

是否命名变量arr的问题
extern int arr[];  // declaration; type is int[]
int arr[10];       // definition; type is int[10]

可转移到单个实体的实体,因此该实体具有不同的类型,具体取决于引用它的上下文(1),或者如果实体的类型始终是相同,只是变量的类型(其名称表示实体)因上下文而异。

(1) 我知道的唯一其他情况适用于 is for enumerators(它们是实体),它们具有不同的类型,具体取决于它们是否从枚举内部引用定义它们(类型是枚举的基础类型)或从外部定义(类型是枚举的类型)。

问题

详情

[basic]/3entity 定义为:

An entity is a value, object, reference, function, enumerator, type, class member, bit-field, template, template specialization, namespace, or parameter pack.

[dcl.stc]/5 涵盖了 extern 说明符,以及它如何应用于 declare a variable

The extern specifier shall be applied only to the declaration of a variable or function. [...]

[basic]/6 变量 定义为:

A variable is introduced by the declaration of a reference other than a non-static data member or of an object. The variable's name, if any, denotes the reference or object.

从这里看来,根据 [basic]/4 and [basic]/5extern 变量声明(必须有名称)并不是特例,它的名称确实表示一个实体:

/4 A name is a use of an identifier, operator-function-id, literal-operator-id, conversion-function-id, or template-id that denotes an entity or label ([stmt.goto], [stmt.label]).

/5 Every name that denotes an entity is introduced by a declaration. Every name that denotes a label is introduced either by a goto statement or a labeled-statement.

因为它声明了一个变量,其名称表示一个对象(这是一个实体).

但是,[intro.object]/1 说:

[...] An object is created by a definition, [...].

[...] An object has a type [...].

但是使用 extern 说明符声明的 variabletype 不一定与 object 在别处 defined(在重新声明变量的非 extern 定义中):

#include <type_traits>

extern int arr[];  // extern declaration
using A = decltype(arr);

int arr[10];       // definition
using B = decltype(arr);

// All asserts below pass.
static_assert(!std::is_same_v<A, B>, "");

static_assert(std::is_same_v<A, int[]>, "");
static_assert(!std::is_same_v<A, int[10]>, "");

static_assert(std::is_same_v<B, int[10]>, "");
static_assert(!std::is_same_v<B, int[]>, "");

如果 extern 变量声明(且仅此)引入的名称 arr 表示一个 实体 ,尤其是一个对象,它可以说这意味着 entity 具有不同的类型,具体取决于 context/scope,这可能会违反 [intro.object]/1 关于对象( entity) 有 "一个 [单一] 类型".

不幸的是,“变量”和“对象”之间的混淆存在于整个标准中(考虑到 [basic.stc.auto] 完全忽略了递归的可能性),包括 which其中一个是“实体”。然而,[basic.types]/6 非常直接地解决了这个问题:

The declared type of an array object might be an array of unknown bound and therefore be incomplete at one point in a translation unit and complete later on; the array types at those two points (“array of unknown bound of T” and “array of N T”) are different types.

对冲“声明的类型”在其他地方使用,如 [dcl.type.auto.deduct] 来谈论为某物“编写”的类型,即使“真实的东西”具有不同的(完成或推导的)类型.这是标准中另一种不幸的描述风格的示例:指定应用于程序的 transformations,但没有明确它们的应用顺序或每个阶段应用的规则。通常很清楚必须应用什么上下文才能使规则有意义:decltype 不考虑指定数组大小的后续声明,也不产生 auto.[=16 类型=]