外部变量声明是否也声明了一个(对象)实体?
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(它们是实体),它们具有不同的类型,具体取决于它们是否从枚举内部引用定义它们(类型是枚举的基础类型)或从外部定义(类型是枚举的类型)。
问题
- 一个
extern
变量声明是否也声明了一个 entity(表示实体的变量名),这样这个实体根据它是否被引用而具有不同的类型通过其 extern
变量声明或其重新声明和定义(int[]
与上面的 int[10]
)?
- 或者,entity 的类型是否总是由对象定义(上面的
int[10]
)指定的类型,而类型的差异只是由于变量的类型 取决于我们引用它的上下文?
详情
[basic]/3 将 entity 定义为:
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]/5,extern
变量声明(必须有名称)并不是特例,它的名称确实表示一个实体:
/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
说明符声明的 variable 的 type 不一定与 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 类型=]
(以下所有标准参考文献均引用 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(它们是实体),它们具有不同的类型,具体取决于它们是否从枚举内部引用定义它们(类型是枚举的基础类型)或从外部定义(类型是枚举的类型)。
问题
- 一个
extern
变量声明是否也声明了一个 entity(表示实体的变量名),这样这个实体根据它是否被引用而具有不同的类型通过其extern
变量声明或其重新声明和定义(int[]
与上面的int[10]
)? - 或者,entity 的类型是否总是由对象定义(上面的
int[10]
)指定的类型,而类型的差异只是由于变量的类型 取决于我们引用它的上下文?
详情
[basic]/3 将 entity 定义为:
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]/5,extern
变量声明(必须有名称)并不是特例,它的名称确实表示一个实体:
/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
说明符声明的 variable 的 type 不一定与 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 ofN
T
”) are different types.
对冲“声明的类型”在其他地方使用,如 [dcl.type.auto.deduct] 来谈论为某物“编写”的类型,即使“真实的东西”具有不同的(完成或推导的)类型.这是标准中另一种不幸的描述风格的示例:指定应用于程序的 transformations,但没有明确它们的应用顺序或每个阶段应用的规则。通常很清楚必须应用什么上下文才能使规则有意义:decltype
不考虑指定数组大小的后续声明,也不产生 auto
.[=16 类型=]