No typename needed before std::list<T>?

396 views
Skip to first unread message

Scott Meyers

unread,
Jan 29, 2005, 1:31:53 AM1/29/05
to
I thought I understood the rules regarding typename, but it seems I was
mistaken. I was under the impression that anytime you refer to a dependent
type name in a template, you had to qualify it with typename. But consider
this:

template<typename T>
class Widget {
typedef typename std::list<T> CollectionType1; // 1
typedef std::set<T> CollectionType2; // 2
};

My expectation was that 1 would compile, but 2 would not. But the three
compilers I have here all accept both. Sigh. Why doesn't 2 require a
typename?

Thanks,

Scott

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std...@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]

Nicolas Pavlidis

unread,
Jan 29, 2005, 9:14:15 AM1/29/05
to
Use...@aristeia.com (Scott Meyers) writes:

> I thought I understood the rules regarding typename, but it seems I was
> mistaken. I was under the impression that anytime you refer to a dependent
> type name in a template, you had to qualify it with typename. But consider
> this:
>
> template<typename T>
> class Widget {
> typedef typename std::list<T> CollectionType1; // 1
> typedef std::set<T> CollectionType2; // 2
> };

I always thought that only nested types have to be qualified with
typename:

template<typename Type>
class Test
{
public:
typedef std::list<Type> TypeList; // :-)
typedef typename std::list<Type>::iterator TypeListIterator;
};

If I remove the typename of the second typedef I'll get a warning under
gcc 3.3 and an errormessage under gcc 3.4.

I'm far away from beeing an expert so I have no good explanation for
this, but maybe it's becaue Templatets can be instantiated with
incomplete types, and so the line marked with the smily wokrs, but the
other line does not, because std::list<Type> is no complete type at this
moment, but it can be nonsense too :-).

Best regards,
Nicolas

--
| Nicolas Pavlidis | Elvis Presly: |\ |__ |
| Student of SE & KM | "Into the goto" | \|__| |
| pav...@sbox.tugraz.at | ICQ #320057056 | |
|-------------------University of Technology, Graz----------------|

Michael Pryhodko

unread,
Jan 29, 2005, 9:14:57 AM1/29/05
to
> template<typename T>
> class Widget {
> typedef typename std::list<T> CollectionType1; // 1
> typedef std::set<T> CollectionType2; // 2
> };
>
> My expectation was that 1 would compile, but 2 would not. But the
three
> compilers I have here all accept both. Sigh. Why doesn't 2 require
a
> typename?

14.6.p2... read twice :) (there is barely visible 'OR')
Bye.
Sincerely yours, Michael.

David B. Held

unread,
Jan 29, 2005, 11:17:12 AM1/29/05
to
Scott Meyers wrote:
> I thought I understood the rules regarding typename, but it seems I was
> mistaken. I was under the impression that anytime you refer to a dependent
> type name in a template, you had to qualify it with typename. But consider
> this:
>
> template<typename T>
> class Widget {
> typedef typename std::list<T> CollectionType1; // 1
> typedef std::set<T> CollectionType2; // 2
> };
>
> My expectation was that 1 would compile, but 2 would not. But the three
> compilers I have here all accept both. Sigh. Why doesn't 2 require a
> typename?

Neither of them do. The compiler already knows that std::list is a
parameterized type. Once you supply a parameter (formal or otherwise),
it, becomes a concrete (typedefable) type. You cannot substitute any
value for T to make std::list<T> anything but a type (say, a value).
On the other hand, the same is not true for std::list<T>::iterator.
Suppose, for the sake of argument, that I perversely defined
std::list<T>::iterator like so:

template <typename T>
struct list
{
typedef T* iterator;
};

template <>
struct list<int>
{
static int const iterator = 42;
};

This is not only perfectly confusing, it's perfectly legal. Now,
does std::list<T>::iterator refer to a type or a value? Without
knowing what T is, you can't say, can you? In order to write
template types that assume one way or the other, you have to give
the compiler a hint as to which one you are writing for. That's
why iterator is a dependent type, and that's why it needs a
typename.

Dave

Bo Persson

unread,
Jan 29, 2005, 1:00:27 PM1/29/05
to

"Scott Meyers" <Use...@aristeia.com> skrev i meddelandet
news:MPG.1c64b696...@news.hevanet.com...

>I thought I understood the rules regarding typename, but it seems I was
> mistaken. I was under the impression that anytime you refer to a
> dependent
> type name in a template, you had to qualify it with typename. But
> consider
> this:
>
> template<typename T>
> class Widget {
> typedef typename std::list<T> CollectionType1; // 1
> typedef std::set<T> CollectionType2; // 2
> };
>
> My expectation was that 1 would compile, but 2 would not. But the
> three
> compilers I have here all accept both. Sigh. Why doesn't 2 require a
> typename?
>

Because std::set is known to be a type, for all T's. So is std::list, so
the typename in 1 isn't needed either.

The problem of deciding what is type comes up when the types are nested.
You could have a specialization, like

template<>
class std::set<some_type>
{
int iterator;
};


typedef typename std::set<T>::iterator iterator_type;


Here you really need typename to indicate that you want the typedef to
work for the cases where iterator really *is* a type, and not for the
cases where it might be something else, like a variable.

For typedefs the compiler might be intelligent enough to expect types
anyway, but for an expression like

typename std::set<T>::value_type * x;

it is impossible to determine if it is a pointer declaration or a
multiplication, unless you know what names are supposed to be types.


Bo Persson

David Abrahams

unread,
Jan 29, 2005, 4:59:13 PM1/29/05
to
Use...@aristeia.com (Scott Meyers) writes:

> I thought I understood the rules regarding typename, but it seems I was
> mistaken. I was under the impression that anytime you refer to a dependent
> type name in a template, you had to qualify it with typename. But consider
> this:
>
> template<typename T>
> class Widget {
> typedef typename std::list<T> CollectionType1; // 1
> typedef std::set<T> CollectionType2; // 2
> };
>
> My expectation was that 1 would compile, but 2 would not. But the three
> compilers I have here all accept both. Sigh. Why doesn't 2 require a
> typename?

First of all, since I know you have it, check out Appendix B of
http://boost-consulting.com/metaprogramming-book.html. I think we've
got the most complete explanation going right now. It lays out all
the groundwork for understanding this.

The compiler needs typename to help it distinguish when a name refers
to a type. You can't even compile

typedef std::set<T> CollectionType2;

unless the compiler has seen a declaration for std::set<T>, and
nothing you can do with specializations or otherwise will change the
fact that std::set is a class template and std::set<T> is a type.

The reason the compiler needs to see typename in

typedef typename std::set<T>::iterator iterator2;

is twofold: first, you might not have shown it the primary template
definition for std::set; that line should compile even after only
seeing

namespace std {
template <class T, class A> class set;
}

Second, whether std::set<T>::iterator is a type could depend on the
actual T you are passed. For example,

template <class T>
struct set<T*>
{
enum { iterator };
}

Whoops; set<T*>::iterator is not a type.

HTH,

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

Scott Meyers

unread,
Jan 29, 2005, 8:44:01 PM1/29/05
to
On Sat, 29 Jan 2005 21:59:13 GMT, David Abrahams wrote:
> First of all, since I know you have it, check out Appendix B of
> http://boost-consulting.com/metaprogramming-book.html. I think we've
> got the most complete explanation going right now. It lays out all
> the groundwork for understanding this.

It's nice, but it has the disadvantage of defining "dependent name" in a
way I find hard to understand, much less explain. As the author of source
code, how am I to know when the "syntactic role" played by an identifier
depends on what type a type parameter turns out to be? Section 9.3.2 of
Vandevoorde and Josuttis is more precise, but it requires that I understand
what a qualified name is, and I find that hard to do, even though they do
their best to define it in table 9.2. Further complicating matters is the
Standard, which, as is often the case regarding templates, is essentially
impossible to understand. IMO.

Anyway, I do understand why typename is needed to disambiguate the meaning
of nested typedefs in dependent type names (e.g, Foo<T>::Widget). And I
guess I understand that compilers can tell whether Foo<T> is a type for any
template Foo and type T, so there's no need for typename in that case.

I still think it would be easier to understand and explain if the rule were
that all dependent type names must be preceded by typename, but I now
understand that that's not the rule, and I thank everybody who contributed
to my new understanding of the situation.

Scott

David Abrahams

unread,
Jan 30, 2005, 9:07:44 PM1/30/05
to
Use...@aristeia.com (Scott Meyers) writes:

> On Sat, 29 Jan 2005 21:59:13 GMT, David Abrahams wrote:
>> First of all, since I know you have it, check out Appendix B of
>> http://boost-consulting.com/metaprogramming-book.html. I think we've
>> got the most complete explanation going right now. It lays out all
>> the groundwork for understanding this.
>
> It's nice, but it has the disadvantage of defining "dependent name" in a
> way I find hard to understand, much less explain. As the author of source
> code, how am I to know when the "syntactic role" played by an identifier
> depends on what type a type parameter turns out to be?

That description is not meant to be a definition; it's designed to
give "a feel" for what's going on. The precise rules are in section
B.2.

> Section 9.3.2 of Vandevoorde and Josuttis is more precise

Did you stop reading before you got to Section B.2?

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

---

goo...@vandevoorde.com

unread,
Jan 30, 2005, 9:07:35 PM1/30/05
to

Scott Meyers wrote:
[...]

> I still think it would be easier to understand and explain if the
rule were
> that all dependent type names must be preceded by typename, but I now
> understand that that's not the rule, and I thank everybody who
contributed
> to my new understanding of the situation.

I think I agree the "rules" are a bit too complicated right now.
More precisely, I think it's okay for the rules to be complicated,
but you should be able to get away with a simple "rule of thumb"
(which may not be optimal in terms of amount of source code,
but which doesn't requiring "trying out the various combinations
until the compiler eats it").

The Core Working Group has been working both on allowing the
"typename" disambiguator in more places, and on requiring it in
fewer places (both of those are good trends IMO).

Oh, and here is another "interesting" illustration of the current
rules; this is a test for the compiler's understanding of so-called
"injected class names":

struct N {
typedef char C;
};

template<typename> struct B {
typedef long L;
};

template<typename T> struct S: N, B<T> {
typedef int I;
S<T>::I i; // Okay
S<T>::C c; // Okay
S::L l; // Error: typename required
};

(Sorry, I cannot resist ;-)

Daveed

Gianni Mariani

unread,
Jan 31, 2005, 1:25:36 AM1/31/05
to
goo...@vandevoorde.com wrote:
...

>
> Oh, and here is another "interesting" illustration of the current
> rules; this is a test for the compiler's understanding of so-called
> "injected class names":
>
> struct N {
> typedef char C;
> };
>
> template<typename> struct B {
> typedef long L;
> };
>
> template<typename T> struct S: N, B<T> {
> typedef int I;
> S<T>::I i; // Okay
> S<T>::C c; // Okay
> S::L l; // Error: typename required
> };

Are you sure ?

gcc (GCC) 4.0.0 20050102 (experimental) says:

typename_nonsense.cpp:11: error: expected ‘;’ before ‘i’
typename_nonsense.cpp:12: error: expected ‘;’ before ‘c’
typename_nonsense.cpp:13: error: expected ‘;’ before ‘l’

Similar errors from MSVC++ 2003.

Although http://www.comeaucomputing.com/tryitout does seem to agree with
you.

g++ (GCC) 3.2.2 20030222 (Red Hat Linux 3.2.2-5) also seems to agree
with you.

What a mess...

Ben Hutchings

unread,
Jan 31, 2005, 1:22:31 PM1/31/05
to
Gianni Mariani wrote:
> goo...@vandevoorde.com wrote:
> ...
>>
>> Oh, and here is another "interesting" illustration of the current
>> rules; this is a test for the compiler's understanding of so-called
>> "injected class names":
>>
>> struct N {
>> typedef char C;
>> };
>>
>> template<typename> struct B {
>> typedef long L;
>> };
>>
>> template<typename T> struct S: N, B<T> {
>> typedef int I;
>> S<T>::I i; // Okay
>> S<T>::C c; // Okay
>> S::L l; // Error: typename required

Presumably most compilers will treat at least S<T> as dependent,
whereas S<T> and S should logically be treated as locally declared and
therefore non-dependent?

>> };
>
> Are you sure ?
>
> gcc (GCC) 4.0.0 20050102 (experimental) says:
>

> typename_nonsense.cpp:11: error: expected ?;? before ?i?
> typename_nonsense.cpp:12: error: expected ?;? before ?c?
> typename_nonsense.cpp:13: error: expected ?;? before ?l?


>
> Similar errors from MSVC++ 2003.

This is not terribly surprising, as I think the code is ill-formed
according to the current standard. But see
<http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#224>.

> Although http://www.comeaucomputing.com/tryitout does seem to agree with
> you.

Given that David works on the front-end used by the Comeau compiler,
that's not surprising.

> g++ (GCC) 3.2.2 20030222 (Red Hat Linux 3.2.2-5) also seems to agree
> with you.

It doesn't implement two-phase name resolution.

> What a mess...

--
Ben Hutchings
Larkinson's Law: All laws are basically false.

goo...@vandevoorde.com

unread,
Jan 31, 2005, 1:23:19 PM1/31/05
to

Gianni Mariani wrote:
> goo...@vandevoorde.com wrote:
> ...
> >
> > Oh, and here is another "interesting" illustration of the current
> > rules; this is a test for the compiler's understanding of so-called
> > "injected class names":
> >
> > struct N {
> > typedef char C;
> > };
> >
> > template<typename> struct B {
> > typedef long L;
> > };
> >
> > template<typename T> struct S: N, B<T> {
> > typedef int I;
> > S<T>::I i; // Okay
> > S<T>::C c; // Okay
> > S::L l; // Error: typename required
> > };
>
> Are you sure ?

Yes. It's a consequence of the resolution of core issue 224
(which improves the definition of "dependent type").

Daveed

Jonathan Turkanis

unread,
Jan 31, 2005, 10:18:01 PM1/31/05
to
Gianni Mariani wrote:
> goo...@vandevoorde.com wrote:

>> Oh, and here is another "interesting" illustration of the current
>> rules; this is a test for the compiler's understanding of so-called
>> "injected class names":
>>
>> struct N {
>> typedef char C;
>> };
>>
>> template<typename> struct B {
>> typedef long L;
>> };
>>
>> template<typename T> struct S: N, B<T> {
>> typedef int I;
>> S<T>::I i; // Okay
>> S<T>::C c; // Okay
>> S::L l; // Error: typename required
>> };
>
> Are you sure ?

> Although http://www.comeaucomputing.com/tryitout does seem to agree
> with you.

I 'm not sure this is entirely a coincidence ;-)

Jonathan

msalters

unread,
Jan 31, 2005, 10:18:35 PM1/31/05
to

Gianni Mariani wrote:
> goo...@vandevoorde.com wrote:
> ...
> >
> > Oh, and here is another "interesting" illustration of the current
> > rules; this is a test for the compiler's understanding of so-called
> > "injected class names":
> >
> > struct N {
> > typedef char C;
> > };
> >
> > template<typename> struct B {
> > typedef long L;
> > };
> >
> > template<typename T> struct S: N, B<T> {
> > typedef int I;
> > S<T>::I i; // Okay
> > S<T>::C c; // Okay
> > S::L l; // Error: typename required
> > };
>
> Are you sure ?
>
> gcc (GCC) 4.0.0 20050102 (experimental) says:
>
> typename_nonsense.cpp:11: error: expected ';' before 'i'
> typename_nonsense.cpp:12: error: expected ';' before 'c'
> typename_nonsense.cpp:13: error: expected ';' before 'l'
>
> Similar errors from MSVC++ 2003.
>
> Although http://www.comeaucomputing.com/tryitout does seem to agree
with
> you.

If you know how Comeau works, and where Daveed works, that's not a
very big surprise ;)

> g++ (GCC) 3.2.2 20030222 (Red Hat Linux 3.2.2-5) also seems to agree
> with you.
>
> What a mess...

Yep. It's complicated.
/Without/ looking at the standard, I'd say the difference is that
S names both a class and a template inside the definition of S. The
form S<T>::I refers to the current class, but the explicit use of T
defers name lookup to instantiation.

In the form S::L, the name L is not looked up in a base class during
the first phase, yet without lookup it's not known whether it names
a type.

i.e. the typename rules differ between the two phases of name lookup
in templates.

Looking at WP1655 (draft standard),
the relevant wording does appear to be similar:
S is indeed "injected" (9) which means it names both the class and
the template (which is why you can write both S and S<T>). However,
they are equivalent.

However, the injected name (S) is just as dependent as the form
S<T> (which is obviously dependent). Both name the "current
instantiation". Hence, S::C and S<T>::C are also equivalent
( but S::I is not equivalent with S::L).

14.6/3 explains when typename is required: "A qualified-id that
refers to a type and in which the nested-name-specifier depends
on a template-parameter (14.6.2) but does not refer to a member
of the current instantiation (14.6.2.1) shall be prefixed by
the keyword typename"

Now, both S::I and S::L are qualified-id's which do depend on
<T>. So, is there anything special about the "member of the
current instantiation" term? It's defined in 14.6.2.1. Both
S::I and S::L are members of the current instantiation (and
so is S::X, even though there's no X in S - yet).

So, in the current draft neither form requires typename. I'd
expect gcc 4 to follow the current draft.

HTH,
Michiel Salters

NB. "Unqualified name" is a rather important term, but it's not
formally defined. Is this a Defect? Or is it just any name that's
not a qualified name? That leaves us with the question, what's
a "Qualified name"? Obviously, there's a close relation to
qualified-id's and unqualified-id's, as defined in 5.1

Scott Meyers

unread,
Jan 31, 2005, 11:42:20 PM1/31/05
to
On Mon, 31 Jan 2005 02:07:44 GMT, David Abrahams wrote:
> Did you stop reading before you got to Section B.2?

Actually, yes. You guys moved on to a new topic ("Problem Two"), so I
thought you were done with the old topic ("Problem One"). Silly somebody.
Maybe me. Maybe you. Maybe both of us. I'm not sure. Anyway, B.2 does
offer a much more detailed blow by blow of the situation.

Scott

Gabriel Dos Reis

unread,
Feb 1, 2005, 12:06:17 AM2/1/05
to
goo...@vandevoorde.com writes:

| Gianni Mariani wrote:
| > goo...@vandevoorde.com wrote:
| > ...
| > >
| > > Oh, and here is another "interesting" illustration of the current
| > > rules; this is a test for the compiler's understanding of so-called
| > > "injected class names":
| > >
| > > struct N {
| > > typedef char C;
| > > };
| > >
| > > template<typename> struct B {
| > > typedef long L;
| > > };
| > >
| > > template<typename T> struct S: N, B<T> {
| > > typedef int I;
| > > S<T>::I i; // Okay
| > > S<T>::C c; // Okay
| > > S::L l; // Error: typename required
| > > };
| >
| > Are you sure ?
|
| Yes. It's a consequence of the resolution of core issue 224
| (which improves the definition of "dependent type").

yes, but that resolution is "bogus", as I pointed out to John at the last
meeting. He agreed there is a problem with it and he said he will
look into it.

I would like to express (again) my strong opposition to all those
"imporvements in small". Improvements should be made considering how
it makes the overall language better, more uniform. Rules with long
list of special cases are good recipes for confusion.
:-(

--
Gabriel Dos Reis
g...@cs.tamu.edu
Texas A&M University -- Department of Computer Science
301, Bright Building -- College Station, TX 77843-3112

Gianni Mariani

unread,
Feb 1, 2005, 12:06:18 AM2/1/05
to
goo...@vandevoorde.com wrote:
> Gianni Mariani wrote:
>
>>goo...@vandevoorde.com wrote:
>>...
>>
>>Are you sure ?
>
>
> Yes. It's a consequence of the resolution of core issue 224
> (which improves the definition of "dependent type").
>

Relevant gcc bug.

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=9634
[DR224] Injected class name as qualifier should not make the name dependent

It appears the GCC guys are waiting for a confirmation on the DR.

From the bug:
> Removing the target milestone because the DR is questionable.

Gabriel Dos Reis

unread,
Feb 1, 2005, 12:21:26 AM2/1/05
to
goo...@vandevoorde.com writes:

[...]

| Oh, and here is another "interesting" illustration of the current
| rules; this is a test for the compiler's understanding of so-called
| "injected class names":
|
| struct N {
| typedef char C;
| };
|
| template<typename> struct B {
| typedef long L;
| };
|
| template<typename T> struct S: N, B<T> {
| typedef int I;
| S<T>::I i; // Okay
| S<T>::C c; // Okay
| S::L l; // Error: typename required
| };


I point out those "interesting" aspects to John at the last meeting.
(One can exhibit many such examples in real-world code setting. The
limitation -- not an improvement -- buys more troubles, confusion than
any good thing worth the trouble).

:-(

The core resolution is bogus. John said he will look into it.

--
Gabriel Dos Reis
g...@cs.tamu.edu
Texas A&M University -- Department of Computer Science
301, Bright Building -- College Station, TX 77843-3112

---

Gabriel Dos Reis

unread,
Feb 2, 2005, 1:31:50 AM2/2/05
to
"msalters" <Michiel...@logicacmg.com> writes:

| Gianni Mariani wrote:
| > goo...@vandevoorde.com wrote:
| > ...
| > >
| > > Oh, and here is another "interesting" illustration of the current
| > > rules; this is a test for the compiler's understanding of so-called
| > > "injected class names":
| > >
| > > struct N {
| > > typedef char C;
| > > };
| > >
| > > template<typename> struct B {
| > > typedef long L;
| > > };
| > >
| > > template<typename T> struct S: N, B<T> {
| > > typedef int I;
| > > S<T>::I i; // Okay
| > > S<T>::C c; // Okay
| > > S::L l; // Error: typename required
| > > };

[...]

| However, the injected name (S) is just as dependent as the form
| S<T> (which is obviously dependent). Both name the "current
| instantiation". Hence, S::C and S<T>::C are also equivalent
| ( but S::I is not equivalent with S::L).
|
| 14.6/3 explains when typename is required: "A qualified-id that
| refers to a type and in which the nested-name-specifier depends
| on a template-parameter (14.6.2) but does not refer to a member
| of the current instantiation (14.6.2.1) shall be prefixed by
| the keyword typename"
|
| Now, both S::I and S::L are qualified-id's which do depend on
| <T>. So, is there anything special about the "member of the
| current instantiation" term? It's defined in 14.6.2.1. Both
| S::I and S::L are members of the current instantiation (and
| so is S::X, even though there's no X in S - yet).
|
| So, in the current draft neither form requires typename. I'd
| expect gcc 4 to follow the current draft.

I can't make sense of that.

If S::L is considered non-dependent, what is it? Type? Nontype?

And yes I agree that since S::X is equivalent to S<T>::X (e.g. injected
class-name), either both are dependent or non-dependent. I don't
believe it is a good thing to make one dependent and the other not.


--
Gabriel Dos Reis
g...@cs.tamu.edu
Texas A&M University -- Department of Computer Science
301, Bright Building -- College Station, TX 77843-3112

---

msalters

unread,
Feb 4, 2005, 11:00:39 PM2/4/05
to

I think you'll discover during instantiation that it's a type. But
isn't it clear S::L is dependent? The important part is whether
they're a member of the current instantiation (14.6.2.1).

It looks like we've found a hole where we again need to consider
the base classes during template compilation. We don't consider
base class members when looking up unqualified names for
expressions, hence the idiom of writing this->baseClassMember in
templates, but apparently we'll need to deal with base class
member types as well.

HTH,
MichielSalters

goo...@vandevoorde.com

unread,
Feb 4, 2005, 11:00:26 PM2/4/05
to
Gabriel Dos Reis wrote:
> goo...@vandevoorde.com writes:
[...]

> | Yes. It's a consequence of the resolution of core issue 224
> | (which improves the definition of "dependent type").
>
> yes, but that resolution is "bogus", as I pointed out to John at the
last
> meeting. He agreed there is a problem with it and he said he will
> look into it.

I don't think "bogus" is the right word. There is a small wording
issue in the proposed text that causes it to not fully reflect what
the working group intended. Overall, though, it's sound.

(In my example S::L would not be dependent according to a strict
reading of the current words.)

> I would like to express (again) my strong opposition to all those
> "imporvements in small". Improvements should be made considering how
> it makes the overall language better, more uniform.

I agree with the latter sentence, except for the "more uniform" part.
It should only be made "more uniform" if that's what's best. It's
indeed
often indeed best to make things uniform, but not always.

Conversely, "improvements in the small" are often very useful to
bettering
the language. Sometimes more so than "grand novelties".

An example of that is the "double right angle brackets" issue.
Unformity is what we have imposed so far, forcing programmers to
add whitespace between closing angle brackets. If the proposal
currently on the table passes, that will no longer be necessary and
we'll be able to write
vector<list<int>>::iterator p; // Syntax error in C++03.
to our hearts' content. A good thing, IMO, and it took an "additional
small and very special rule" to get there.

Wrt. 224, I think it's generally a good direction to go. In fact, I
would
like to see many more special little rules to make "typename"
unnecessary in various places where it is now required (e.g., the first
type-name token of a class or namespace scope declaration or the
first type-name token of a typedef declaration in which "typedef" is
the first token), plus one more general (but still little) rule, that
allows
"typename" where it's not really needed just so programmers can use
a simple "rule of thumb" to decide when to use that token (e.g., "you
can use typename before any type name that contains a '::'").

That would help the incidental programmer (borrowing Francis'
term) to program with confidence, while also allowing the more
knowledgable programmers to unclutter their source code.
Daveed

Gabriel Dos Reis

unread,
Feb 10, 2005, 12:16:15 PM2/10/05
to
"msalters" <Michiel...@logicacmg.com> writes:

But that is not how templates work. At the definition point, it is
required to know whether the symbol denotes a type or not. The
default rule is that unless explicit annotations (i.e. typename, or
previous declarations) have been provided, it is not a type. There is
no afterward discovery at instantiation time.

| isn't it clear S::L is dependent? The important part is whether
| they're a member of the current instantiation (14.6.2.1).

The issue is not whether S::L is clearly dependent or not. The real
issue is whether both S<T>::L and S::L are dependent.

Old rules say they are, and as such typename is required, because of
the dependent qualifier S<T>. Similarly, old rules require typename
for S<T>::I and S<T>::C, which the DR-224
wanted to improve on, with the result that S::L is invalid.


I think the issue has a root in the fact that there is a tendency to
equate dependent type with requirement to annotate with "typename".
What DR #224 should have said, I think, is:
(1) applicable lookup is performed;
(2) if declarations are found, then usual rules are applied;
(3) otherwise, the qualified name is assumed to designate a nontype,
unless explicitly annotated with "typename".

Put differently: if a declaration is found, that is it; otherwise you
need annotation to say it is a type.

Notice, with that rule:

(1) S<T>::I is dependent, but does not need "typename" annotation
because there is a declaration in scope.

(2) S<T>::C is dependent but that does not need "typename"
annotation because a declaration is found in the non-dependent
base class C.

(3) S<T>::L is dependent, and would need annotation to pretend it
names a type.


Saying that the things found in the current instantiation are not
dependent is IMHO both confusing and symptomatic of the idea of
equating dependent type with "typename" annotation.
That isn't right. S<T>::X can be dependent (in the obvious sense)
even if it has a declaration in S<T>.

--
Gabriel Dos Reis
g...@cs.tamu.edu
Texas A&M University -- Department of Computer Science
301, Bright Building -- College Station, TX 77843-3112

---

Reply all
Reply to author
Forward
0 new messages