Re: Is it a g++-4.1 bug ?
Greg Herlihy schrieb:
The "typename" keyword would be needed only if "inner" a) named a type and
b) depended upon a template parameter for its successful resolution. But
because "inner" names a template and not a type, and because the inner class
template is defined within the "test" class template itself (and not in the
context of any type), the "typename" keyword should not appear here.
Not true, see:
14.6/3:
"A qualified-id that refers to a type and in which the nested-name-
specifier
depends on a template-parameter (14.6.2) shall be prefixed
by the keyword typename to indicate that the qualified-id
denotes a type, forming an elaborated-type-specifier (7.1.5.3).
elaborated-type-specifier:
.. . .
typename ::_opt nested-name-specifier identifier
typename ::_opt nested-name-specifier templateopt template-id
"
and here the definition of nested-name-specifier:
5.1/7:
"nested-name-specifier:
class-or-namespace-name :: nested-name-specifier_opt
class-or-namespace-name :: template nested-name-specifier"
(Note that I used underscores to emphasize subscripts,
as in _opt)
The compiler knows that inner is not a type, but a template. The compiler
also knows that inner<I> must be a template-id because the preceding
"template <typename I>" announces it as such.
This is not convincing (to me). 14.2/4 says:
"When the name of a member template specialization appears
after . or -> in a postfix-expression, or after nested-name-specifier
in a qualified-id, and the postfix-expression or qualified-id
explicitly
depends on a template-parameter (14.6.2), the member template
name must be prefixed by the keyword template."
and we have the "nested-name-specifier" situation here.
If the compiler sees "test<T>::inner<I>" it cannot be sure that
inner<I> *is* a type due to template specialization freedom - so
this is no real counterevidence. Consider
template <typename T>
struct A {
template <typename U>
struct B {
typedef U Type;
};
};
template <typename T, typename U>
typename A<T>::template B<U>::Type foo();
Comeau (which you mentioned) *requires* both
typename and template here, the alternative
template <typename T, typename U>
A<T>::B<U>::Type foo();
will *not* be accepted:
"Comeau C/C++ 4.3.8 (Aug 19 2006 13:36:48) for
ONLINE_EVALUATION_Alpha1
Copyright 1988-2006 Comeau Computing. All rights reserved.
MODE:strict errors C++
"ComeauTest.c", line 10: error: nontype "A<T>::B [with T=T]" is not a
template,
Should it be XX::nontype "A<T>::B [with T=T]"?, where XX is some
namespace?
Did you #include the right header?
A<T>::B<U>::Type foo();
^
"
The whole story reduces to the decision: From
which lexical point on is A<T>::B<U> in *the scope* of
the template A<T>::B<U>? Every compiler I know of
considers everything *behind* the *qualifying* template-id
as inserted class-name. This is simple, because 9/2 is
very clear here:
"A class-name is inserted into the scope in which it is
declared immediately after the class-name is seen. The
class-name is also inserted into the scope of the class
itself; this is known as the injected-class-name."
So practically no compiler has problems at all with this:
template <typename T>
struct A2 {
template <typename U>
struct B2 {
typedef U Type;
void foo(Type); // Note: Type is the inserted A2<T>::B2<U>::Type
};
};
template <typename T>
template <typename U>
void A2<T>::B2<U>::foo(A2<T>::B2<U>::Type){}
simply because
template <typename T>
template <typename U>
void A2<T>::B2<U>::foo(Type){}
would be valid as well. But try now
template <typename T>
struct A3 {
template <typename U>
struct B3 {
typedef U Type;
A3<T>::B3<U>::Type foo();
};
};
template <typename T>
template <typename U>
Type A3<T>::B3<U>::foo() { return U(); }
Should this be valid? Nope, it's not, because Type
is not yet in the scope of A3<T>::B3<U>.
template<typename T>
template<typename I>
const typename test<T>::template inner<I>& ...
Because "typename" and "template" identify different type-dependent names,
no one name would ever require that both keywords be applied to it. So the
fact that gcc would requires both "typename" and "template" for the name
"inner" could not be a valid C++ requirement - but could only be caused by a
bug in the compiler.
Chapter and verse, please. IMO your interpretation (and
that of Comeau) bases on the post-14882-2003 area, because
the wording has strongly changed since then (introducing the
concept of "current instantiation"), which does not exist in the
currently valid 14882-2003.
But even with the new wording I cannot read what you read,
e.g.
14.6/3:
"When a qualified-id is intended to refer to a type that is not a
member of the current instantiation (14.6.2.1) and its
nested-name-specifier depends on a template-parameter (14.6.2),
it shall be prefixed by the keyword typename, forming a
typename-specifier. If the qualified-id in a typename-specifier does
not denote a type, the program is ill-formed.
typename-specifier:
typename ::opt nested-name-specifier identifier
typename ::opt nested-name-specifier templateopt simple-template-id
"
14.6.2.1/1:
"In the definition of a class template, a nested class of a class
template, a member of a class template, or a member of a
nested class of a class template, a name refers to the current
instantiation if it is
- the injected-class-name (9) of the class template or nested class,
- in the definition of a primary class template, the name of the
class template followed by the template argument list of the primary
template (as described below) enclosed in <>,
- in the definition of a nested class of a class template, the name
of the nested class referenced as a member of the
current instantiation, or
- in the definition of a partial specialization, the name of the
class
template followed by the template argument list of the partial
specialization enclosed in <>."
IMO none of these conditions apply here.
What have I overlooked, that Comeau is convinced, that
it interpretes the standard correctly? I would really love
to see the proper proof (or the obvious error in my argumentation
chain) and I have no ill-will to Comeau at all.
Greetings from Bremen,
Daniel Kr?gler
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]