Document number: | 00-0008/N1231 |
Date: | March 7, 2000 |
Author: | John Spicer, Edison Design Group |
jhs@edg.com |
This document discusses several issues that I volunteered to work on between meetings:
In my original reflector posting on this subject I recommended that
the standard be changed to require that the template
keyword be followed by a template-id (i.e., a name followed by
a template-argument-list).
The following example gives the rationale for this recommendation.
The template
keyword is only supposed to provide syntactic
disambiguation, not affect name lookup (just as is the case with the
typename
keyword). This results in the surprising behavior
that call #2 does not call the template function.
template
keyword
is needed in the default argument to indicate that T::C
is
a template, just as typename
would be required if
T::C
were a type.
template
keyword without a following template-id
.
If we allow the template keyword to be followed by a name without a template-argument-list we must then decide what it means for functions in such cases (i.e., we must resolve the issue illustrated by the first example above). For classes it is not an issue (if the name is followed by a template-argument-list, it refers to a specialization of the class template, if not, it refers to the class template itself).
There are two possible interpretations that I can think of:
template
keyword is applied to an overload set
containing both template and non-templates, the non-templates are ignored.
In other words, it is treated as if the name were followed by an
empty template-argument-list (i.e., <>
).
template
keyword is followed by a name that does
not have a template-argument-list, the program is ill-formed
if the name refers to anything except a class template (i.e., it cannot
refer to a function, function template, or overload set).
The first option has the benefit of being (presumably) what people would
find most natural. The second has the benefit of retaining the
property that the template
keyword is for syntactic guidance
without semantic implications.
This is the proposed wording change for core issue 108.
Add after 14.6.1 paragraph 2:
Within the scope of a class template, when the unqualified name of a nested class of the class template is referred to, it is equivalent to the name of enclosing class template followed by the name of the nested class. [Example:template --end example]struct A { class B {}; // B is equivalent to A::B, which is equivalent to A ::B // which is dependent. class C : B { }; };
This issue was discussed on the reflector and may already be in the updated core issues list.
There is a problem with the dependency rules when referring to members of the "current instantiation" of a class template. The example below (a modified version of Derek Inglis' example from core-8387) illustrates that the name used to refer to an entity can render the same entity either dependent or non-dependent.
I believe this behavior is surprising, and that programmers would expect
that whether you refer to the members as A
,
a
, and a2
or S::A
,
S::a
and S::a2
or S<T>::A
,
S<T>::a
and S<T>::a2
, the behavior should be
the same.
Note that the behavior should only be the same when you refer
to the template-id that is equivalent to the unqualified template name
as described in 14.6.1p1. Something like S<T*>::A
would not be
equivalent to S::A
or A
.
S<T>::a
is dependent because the id-expression
contains a template-id that is dependent. Likewise,
S::a
is dependent because it is defined as being
equivalent to S<T>::a
. As far as I can tell, plain
a
is not dependent while this->a
is. If
plain a
is not dependent then neither is plain
A
, making a2
also non-dependent.
a3
is dependent though, because its type was declared
using a dependent syntax.
I don't think these rules are reasonable.
An id-expression should be dependent if its type is dependent. The
form of the identifier reference should not make a difference.
Similarly, the type of a
, a2
, and
a3
should be known to be int
, and none of
them should be considered dependent.
The standard would need to be clarified to say that within the scope
of S
you can look up things like S::A
or
S<T>::A
to find out the type denoted by A
(note that this does not apply to looking up something like
S<T*>::A
).