Closed xmh0511 closed 5 months ago
It seems that const T
are normatively specified by [temp.param] p8 and [expr.prim.id.unqual] p3.
[temp.param] p8 states (emphasis mine):
An id-expression naming a non-type template-parameter of class type
T
denotes a static storage duration object of typeconst T
, known as a template parameter object, [...]
So the id-expression denotes the template parameter object. Per [expr.prim.id.unqual] p3, the result of the id-expression is that template parameter object, and the type of the id-expression is that of the template parameter object, i.e., const T
.
(The id-expression is also specified to be an lvalue in [expr.prim.id.unqual] p3.)
Perhaps the current wording is a bit ambiguous. In [temp.param] p8, "of class type T
" should be associated to "a non-type template-parameter", not "an id-expression".
In this
decltype(id-expression)
, GCC and Clang have divergence, GCC says the type isconst T
while Clang says it isT
.struct A{}; template<auto const a> void show(){ decltype(a) b; A& rf = b; } int main(){ show<A{}>(); }
The template parameter is of type A
in this example. The top-level const
is dropped ([temp.param] p6). So gcc is buggy here, which is known (GCC Bug 99631).
"denote" in [expr.prim.id.unqual] p3 merely means it denotes the entity that is introduced by the declaration that declares the name(i.e. id-expression) for which name lookup finds the declaration, which is statically determined. Since the id-expression is introduced by the parameter-declaration(i.e. A a
), its declared type should be A
.
Moreover, "denote an object" does not mean the lvalue is required to be that type of object, for example:
int a;
const int& ref = a;
According to [expr.type] p1
The expression designates the object or function denoted by the reference, and the expression is an lvalue or an xvalue, depending on the expression.
The object denoted by the reference is a non-const object, by your logic, the id-expression ref
thereof has type int
? Furthermore, consider this example:
int a = 0;
using Type = int const;
new (&a) Type{1};
Now, the name can arguably say it denotes a const object, so the type of the id-expression is const it
? Presumably, it is not the intent. The type of a name and the type of object it denotes does not have a close connection.
So, [expr.prim.id.unqual] p3 merely mean the type of an id-expression is the declared type of the declaration introducing the name.
"denote" in [expr.prim.id.unqual] p3 merely means it denotes the entity that is introduced by the declaration that declares the name(i.e. id-expression) for which name lookup finds the declaration, which is statically determined.
But a template parameter is arguably not itself an entity (although the term "value" in [basic.pre] p3 is not very clear), while a template parameter object is definitely an entity.
Moreover, "denote an object" does not mean the lvalue is required to be that type of object, for example:
int a; const int& ref = a;
Hmm... it is far less than ideal to use the ambiguous verb "denote", which you should have noticed for many times (cplusplus/draft#5346).
While "denote" is ambiguous, I think we can say a template parameter is not a thing that can be denoted by an id-expression (in the meaning of denoting an entity), so [temp.param] p8 should be considered unambiguously meaning that the id-expression only denotes the template parameter object, and thus have the same type as that object.
I think we should have an omnibus issue that clarifies "denoting", "naming", "designating", and "referring to".
But a template parameter is arguably not itself an entity (although the term "value" in [basic.pre] p3 is not very clear), while a template parameter object is definitely an entity.
The template parameter introduces an object that is an entity, whose declaration is a parameter-declaration, and if there is any other specification, the type of the parameter-declaration is specified by [dcl.meaning], regardless of what actual object it denotes. The declaration just declares the name should denote a certain object, rather than specify which object it denotes.
So, you shouldn't determine the type of the expression according to the type of the object it denotes, instead, there is no special specification, the type of the name/expression should be determined by its declaration.
The template parameter introduces an object that is an entity
Not obviously true to me. I think it's still unclear whether a template parameter object is introduced by a template parameter. Perhaps we can say a template parameter object is introduced and created in some way other than declaration (there're some other objects created in unclear ways, see CWG2334).
IMO a template parameter object is very similar to a variable, but the current wording seemingly intends to distinguish between a template parameter object and a variable. (Perhaps we should continue the discussion in #148.)
A declaration that introduces an object does not necessarily mean the declaration creates the object. Consider this example:
extern A a; // introduces an object but not create it.
IMO a template parameter object is very similar to a variable
The variable is a unified name for either a reference or an object, even though the definition is unclear for what can be called a declaration of an object, however, this is another recorded issue.
As you mentioned above, we first should clear the definition of these verbs: denote, designate, which was discussed in https://github.com/cplusplus/CWG/issues/44#issuecomment-1144135736
When we say a name/expression denotes an entity, it should mean after performing a name lookup, which finds a declaration, that introduces the name, introduces such an entity, i.e. it is a declaration introducing such a kind of entity.
When we say a name/expression designates an object, we intend to mean, it is identified as a specific object, after evaluating it.
CWG2777
Note that decltype is handled specially for non-type template parameters.
Full name of submitter (unless configured in github; will be published with the issue): Jim X
[temp.param.note] p3 says:
Then, in [expr.prim.id.unqual], there is still only a note that says the type of the id-expression, [expr.prim.id.unqual.note] p4
If there is no extra formal rule, then [temp.param] p8 just trumps any note, which says:
T
is the declared type of the id-expression.Suggested Resolution
When an id-expression that denotes the template parameter object appears in a context other than
decltype(id-expression)
, we should define its type with a formal rule.In this
decltype(id-expression)
, GCC and Clang have divergence, GCC says the type isconst T
while Clang says it isT
.https://godbolt.org/z/9jqhYn3vd