X3J16/96-0103
WG21/N0921
Dependent Names in Templates
Author: Erwin Unruh
Email: erwin.unruh@mch.sni.de
Siemens Nixdorf information systems
Based on a new approach for the template compilation model, a change in
the rules rgarding dependent names was made. I used this situation to
think about the rules and tried to complete them. I send those rules to
the reflector.
Unfortunately I was not ably to refine the rules in time for the mailing, so
I just put the refelctor message in the mailing. If I have time I may rework
this paper so we have a better version for the meeting.
Reflector message ext-3611:
> 2. Dependent Names
>
> We propose a simplification of the definition of "dependent name."
> The principal goal is to make this concept more strictly syntactic,
> as suggested in Sean Corfield's editorial box (Box 28).
I welcome this approach (independent from the rest of the proposal). But I
think the rules given are not accurate enough. I will give a more precise set
of rules.
When working on this, I made a subtle change in my perception. The usual view
is that a type is dependent. I gave up that idea and say that a "type-id"
is dependent. It may be questionable whether T in
template < typename T > void foo(T);
foo(1);
is a type or not. I think it is a placeholder for a type. So the question
whether T is int is meaningless for the definition per se. It becomes a meaning
when processing an instantiation.
On the same grounds I defined the attribute of being dependent only for
expressions, not for their type. The result, of whether a certain piece of
code is dependent is not changed.
When drafting the following rules I made a few substantive changes:
- I considered type, value and template parameters.
- The original wording does allow a name to be dependent in one instantiation
and not be dependent in another. I follow the rule that a name is dependent
in all or no instantiation. So the attribute can be determined looking at
the definition alone.
This makes some programs ill-formed. They are:
- where the template parameter is a type already used in the template
void f(int);
template void foo(T t){
f(1.0); // not dependent
};
void f(double);
foo(1.0);
- where a conversion to a template parameter is used to call a function.
class A { };
class B { operator A(); };
template void foo(T t) {
B b;
f(b);
}
void f(A);
foo(A);
- I tried to get a somehow minimal set of dependent names. So as example
f(sizeof(T))
is not dependent, because the argument type is int.
- I introduced 3 targets of "dependent": a type-id being (type-)dependent, when
the represented type depends; an expression being type-dependent, when its
type depends; and a constant-expression being value-dependent, when its value
depends.
I am using the term "type-id" to describe a syntactic construct describing
a type. It is not identical to the syntactic term type-id.
The rules are :
***************************************************************
The rules for type-id also cover class-id used for scoping.
A type-id depends on a template parameter P if it is of the form
cv T and T depends on P
T* cv opt and T depends on P
T& and T depends on P
T1 T2::* cv opt and T1 or T2 depends on P
T[E] and T depends on P or E value-depends on P
T (T1, .. Tn) cv opt throw( .. ) opt
and T or one of T1 .. Tn depends on P
note: exception specification does not give
dependency
TM and P is TM or one of P1 to Pn depends on P;
when the corresponding parameter is a type, the depedency of
a type-id is used; if it is an integral value,
value-dependency is used; if it is a template or a
non-integral value, see below.
T1 :: T2 and T1 or T2 depends on P
T and T is P or T is a typedef declared with a type-id which
depends on P
A template template argument depends on P if it is either P or of the form
T::TM where T depends on P.
A non-integral non-type template argument depends on P if it is of the form
T::x or &T::x where T depends on P.
(( or when the argument is P ) to be added if they are allowed)
An expression type-depends on a template parameter P if it is of the form
this and the class type of the member function depends on P
T::x and T depends on P
x and x is declared with a type-id which depends on P
operator T and T depends on P
E1[E2] and E1 or E2 depends on P
E(E1, .. En) and E or one of E1 .. En depends on P
T(E)
(T)E
.._cast(E) and T depends on P (regardless of E)
new (E1) T (E2) and T depends on P
E.x
E->x and E depends on P
E.T::x
E->T::x and E depends on P or T depends on P
E++
E--
op E and E depends on P
E1 op E2 and E1 or E2 depends on P
E ? E1 : E2 and E1 or E2 depends on P
An constant-expression value-depends on a template parameter P if it is of
the form
T::x and T depends on P
x and x is P (where P is a value-parameter)
x and x is declared with a type-id which depends on P
x and x is an integral constant initialized with an expression
which value-depends on P
T(E)
(T)E
.._cast(E) and T depends on P or E value-depends on P
sizeof (T) and T depends on P
sizeof E and E type-depends on P
op E and E value-depends on P
E1 op E2 and E1 or E2 value-depends on P
E ? E1 : E2 and E or E1 or E2 value-depends on P
still open: when is a non-integral template-value-argument dependent?
When scanning a template definition, lookup all names present. If a
non-qualified name appears in the position
name ( E1, .. En )
within an expression
and the lookup resolves to a set which only contains functions
(the set may be empty)
and one of the expressions E1 to En type-depends on a parameter P of
the template
then the name is looked up again in the context of the instantiation.
I leave open the semantics of the second lookup and the relationship of
first and second lookup. They may follow the WP rules or some of the
newly proposed rules.
***************************************************************
The list for value-dependency is shorter than for type-dependency because
a whole set of constructs are not allowed in constant expressions. The
intent is that if an expression type-depends on P and is a valid constant
expression, than it also value-depends on P.
The rules clearly favour the first lookup. If the first lookup finds a type
or a variable, a second lookup is not tried. This does even hold if that
variable does not have an operator().
They have the big advantage (especially for compiler vendors) that the set
of names which may be dependent is clearly defined at the point of the
template definition.
I know that the rules above need work to be formed into standardeese. I also
think that there are a few mistakes in the rules.