(All standard references below refers to N4659: March 2017 post-Kona working draft/C++17 DIS, with emphasis mine in the standard quotations)
Background
I'm trying to answer the question whether or not the named variable arr below
extern int arr[]; // declaration; type is int[]
int arr[10]; // definition; type is int[10]
is transferrable to that of a single entity, such that this entity has different type depending on from which context it is referred(1), or if the entity's type is always the same, and it's just the type of the variables (whose name denotes entity) that differs depending on context.
(1) The only other case I know of where this applies is for enumerators (which are entities), which have different type depending on whether they are referred to from inside the enumeration that defines them (the type is that of the underlying type of the enumeration) or from outside of it (the type is that of the enumeration).
Question
- Does an
externvariable declaration also declare an entity (the variable name denoting the entity), such that this entity has a different type depending on whether its referred to by itsexternvariable declaration or its re-declaration and definition (int[]vsint[10]above)? - Or, is the type of the entity always that as specified by the object definition (
int[10]above), whereas the difference in type is only due differences in the type of the variable depending on from what context we refer to it?
Details
[basic]/3 defines an entity as:
An entity is a value, object, reference, function, enumerator, type, class member, bit-field, template, template specialization, namespace, or parameter pack.
[dcl.stc]/5 covers the extern specifier, and how it can be applied to declare a variable:
The
externspecifier shall be applied only to the declaration of a variable or function. [...]
[basic]/6 defines a variable as:
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.
From here, it seems straight-forward, as per [basic]/4 and [basic]/5, that an extern variable declaration (which must have a name) is no special case, and its name does indeed denote an entity:
/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.
as it declares a variable whose name denotes an object (which is an entity).
However, [intro.object]/1 says:
[...] An object is created by a definition, [...].
[...] An object has a type [...].
but the type of a variable declared using the extern specifier is not necessarily the same as that of the object which is defined elsewhere (in the re-declaration an non-extern definition of the variable):
#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[]>, "");
If the name arr as introduced by the extern variable declaration (and only that) denotes an entity, particularly that of an object, it would arguably mean that this entity has a different type depending on context/scope, which would arguably violate [intro.object]/1 regarding an object (entity) to have "a [single] type".