Topic: rationale behind typename
Author: gdr@cs.tamu.edu (Gabriel Dos Reis)
Date: Tue, 18 Jul 2006 15:21:51 GMT Raw View
On Tue, 18 Jul 2006, Richard Smith wrote:
| Gabriel Dos Reis wrote:
| > [...] I must add that I don't see how making it
| > optional will decrease the confusion around "typename".
|
| Making it optional in the sense of allowing it in places where it
| currently is not allowed might improve the situation, though.
|
| template <class T>
| struct foo : typename T::nested_type {
| typedef typename T::nested_type base;
| };
|
| The first typename is currently illegal, the second mandatory. Making
| the former legal (and optional) would decrease confusion, wouldn't it?
|
| (For that matter, as the second use occurs in a typedef, the compiler
| could easily tell that that's supposed to be a typename and make that
| usage optional too. Whether that would decrease confusion is another
| matter.)
|
| And, in my opinion, it would also be useful if "typename" were legal
| (albeit redundant) in non-templates. It's currently legal (and
| redundant) to put "typename" in front of non-dependent types in
| templates; why not go further and allow it outside of templates too?
that is a subject of a DR handled by the core group.
--
Gabriel Dos Reis
gdr@cs.tamu.edu
Texas A&M University -- Department of Computer Science
301, Bright Building -- College Station, TX 77843-3112
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: gennaro_prota@yahoo.com (Gennaro Prota)
Date: Mon, 17 Jul 2006 17:44:47 GMT Raw View
On Mon, 17 Jul 2006 00:58:47 CST, Gabriel Dos Reis <gdr@cs.tamu.edu>
wrote:
>On Sat, 15 Jul 2006, sashan wrote:
>
>| Hi
>|
>| I'm wondering why the std specifies that typename be used in cases like
>| this:
>|
>| typename Foo<T>::bar b2;
>
>unfortunate limitation of parsing technology that shrines in the
>language specification.
So it might be made optional in such cases, in the future? :)
--
Gennaro Prota
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: jdennett@acm.org (James Dennett)
Date: Mon, 17 Jul 2006 19:35:37 GMT Raw View
Gabriel Dos Reis wrote:
> On Sat, 15 Jul 2006, James Dennett wrote:
>
> | sashan wrote:
> | > Hi
> | >
> | > I'm wondering why the std specifies that typename be used in cases like
> | > this:
> | >
> | > typename Foo<T>::bar b2;
> | >
> | > When bar is a type as opposed to a variable? Why can't the compiler
> | > make that decision?
> |
> | Because, assuming T is a dependent type (i.e., a type depending
> | on a template parameter), it's unknowable at the time the template
> | is parsed. There may be some T for which Foo<T>::bar is a type,
> | and others for which it is an integral constant expression (and
> | yet others for which it does not exist, though that's not so
> | relevant here).
>
> but even in those disparate cases, using "typename" does nto make the
> resulting program valid.
I'm afraid I can't understand that; typename is in the language
precisely because it makes the program valid, so long as the
template is used only for suitable types, and because it allows
the template to be parsed without additional knowledge of the
types over which it will be instantiated.
You snipped the paragraph I wrote explaining that in more
detail:
In order to allow templates to be checked for syntax,
the compiler must know for each identifier in the
template whether that identifier refers to a type and
whether it refers to a template. This is why the
keywords typename and template are sometimes needed
in generic code, when they are not required in
non-generic code.
> Consider
>
> Foo<T>::bar * foo;
>
> or
>
> Foo<T>::bar(x);
>
> Irrespective of whether the instantiations of Foo<T> may behave as you
> said, the parser --before going into instantiation considerations--
> still needs clues for deciding whether to parse them as declarations
> or expressions-statements.
Yes, which is why typename is used to distinguish which case
your template intends to support. Without typename, bar is
not a type name in the above, so we have multiplication or
a function call (expression statements), but with typename
they become declarations (with redundant () in the latter).
-- James
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: gdr@cs.tamu.edu (Gabriel Dos Reis)
Date: Mon, 17 Jul 2006 20:43:23 GMT Raw View
On Mon, 17 Jul 2006, Gennaro Prota wrote:
| On Mon, 17 Jul 2006 00:58:47 CST, Gabriel Dos Reis <gdr@cs.tamu.edu>
| wrote:
|
| >On Sat, 15 Jul 2006, sashan wrote:
| >
| >| Hi
| >|
| >| I'm wondering why the std specifies that typename be used in cases like
| >| this:
| >|
| >| typename Foo<T>::bar b2;
| >
| >unfortunate limitation of parsing technology that shrines in the
| >language specification.
|
| So it might be made optional in such cases, in the future? :)
I see your smiley; however I must add that I don't see how making it
optional will decrease the confusion around "typename".
--
Gabriel Dos Reis
gdr@cs.tamu.edu
Texas A&M University -- Department of Computer Science
301, Bright Building -- College Station, TX 77843-3112
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Gabriel Dos Reis <gdr@cs.tamu.edu>
Date: Mon, 17 Jul 2006 16:16:34 CST Raw View
On Mon, 17 Jul 2006, James Dennett wrote:
| Gabriel Dos Reis wrote:
| > On Sat, 15 Jul 2006, James Dennett wrote:
| >
| > | sashan wrote:
| > | > Hi
| > | >
| > | > I'm wondering why the std specifies that typename be used in cases like
| > | > this:
| > | >
| > | > typename Foo<T>::bar b2;
| > | >
| > | > When bar is a type as opposed to a variable? Why can't the compiler
| > | > make that decision?
| > |
| > | Because, assuming T is a dependent type (i.e., a type depending
| > | on a template parameter), it's unknowable at the time the template
| > | is parsed. There may be some T for which Foo<T>::bar is a type,
| > | and others for which it is an integral constant expression (and
| > | yet others for which it does not exist, though that's not so
| > | relevant here).
| >
| > but even in those disparate cases, using "typename" does nto make the
| > resulting program valid.
|
| I'm afraid I can't understand that; typename is in the language
| precisely because it makes the program valid, so long as the
| template is used only for suitable types, and because it allows
| the template to be parsed without additional knowledge of the
| types over which it will be instantiated.
My message was saying that putting "typename" in front of the code
does not make it legal if you instantiate Foo with T=int. That you
can't dispute. I was clarifying that "typename" has no bearing to
instantiation as several messages tried to imply. It is a pure
parsing problem, not instantiation problem.
| You snipped the paragraph I wrote explaining that in more
| detail:
|
| In order to allow templates to be checked for syntax,
| the compiler must know for each identifier in the
| template whether that identifier refers to a type and
| whether it refers to a template. This is why the
| keywords typename and template are sometimes needed
| in generic code, when they are not required in
| non-generic code.
This is alsmot correct; but the earlier instantiation stuff I find
confusing :-)
In fact, it is not really checking for syntax as opposed to letting
the compiler proceed in the parsing. The compiler checks almost
nothing in
Foo<T>::bar(x);
or
typename Foo<T>::bar(x);
It trusts the programmer.
| > Consider
| >
| > Foo<T>::bar * foo;
| >
| > or
| >
| > Foo<T>::bar(x);
| >
| > Irrespective of whether the instantiations of Foo<T> may behave as you
| > said, the parser --before going into instantiation considerations--
| > still needs clues for deciding whether to parse them as declarations
| > or expressions-statements.
|
| Yes, which is why typename is used to distinguish which case
| your template intends to support. Without typename, bar is
| not a type name in the above, so we have multiplication or
| a function call (expression statements), but with typename
| they become declarations (with redundant () in the latter).
I know all that. The question was "what if it wasn't required" :-)
--
Gabriel Dos Reis
gdr@cs.tamu.edu
Texas A&M University -- Department of Computer Science
301, Bright Building -- College Station, TX 77843-3112
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: "Richard Smith" <richard@ex-parrot.com>
Date: Tue, 18 Jul 2006 07:00:53 CST Raw View
Gabriel Dos Reis wrote:
> [...] I must add that I don't see how making it
> optional will decrease the confusion around "typename".
Making it optional in the sense of allowing it in places where it
currently is not allowed might improve the situation, though.
template <class T>
struct foo : typename T::nested_type {
typedef typename T::nested_type base;
};
The first typename is currently illegal, the second mandatory. Making
the former legal (and optional) would decrease confusion, wouldn't it?
(For that matter, as the second use occurs in a typedef, the compiler
could easily tell that that's supposed to be a typename and make that
usage optional too. Whether that would decrease confusion is another
matter.)
And, in my opinion, it would also be useful if "typename" were legal
(albeit redundant) in non-templates. It's currently legal (and
redundant) to put "typename" in front of non-dependent types in
templates; why not go further and allow it outside of templates too?
It can often be impossible to write a single macro that will work in
both tempalted and non-templated code because of this. (And I don't
believe the "don't use macros" argument holds water -- there are many
things, like writing overloaded forwarding functions with an arbitrary
number of function parameters, that are likely to remain unaddressed in
C++0x and will continue to need preprocessor trickery to solve.)
--
Richard Smith
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: "sashan" <sashang@gmail.com>
Date: Sat, 15 Jul 2006 01:19:36 CST Raw View
Hi
I'm wondering why the std specifies that typename be used in cases like
this:
typename Foo<T>::bar b2;
When bar is a type as opposed to a variable? Why can't the compiler
make that decision?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: jdennett@acm.org (James Dennett)
Date: Sat, 15 Jul 2006 12:42:49 GMT Raw View
sashan wrote:
> Hi
>
> I'm wondering why the std specifies that typename be used in cases like
> this:
>
> typename Foo<T>::bar b2;
>
> When bar is a type as opposed to a variable? Why can't the compiler
> make that decision?
Because, assuming T is a dependent type (i.e., a type depending
on a template parameter), it's unknowable at the time the template
is parsed. There may be some T for which Foo<T>::bar is a type,
and others for which it is an integral constant expression (and
yet others for which it does not exist, though that's not so
relevant here).
In order to allow templates to be checked for syntax, the
compiler must know for each identifier in the template whether
that identifier refers to a type and whether it refers to a
template. This is why the keywords typename and template are
sometimes needed in generic code, when they are not required
in non-generic code.
-- James
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: "Peter C. Chapin" <pchapin@sover.net>
Date: Sat, 15 Jul 2006 07:56:51 CST Raw View
sashan wrote:
> I'm wondering why the std specifies that typename be used in caseslike
> this:
>
> typename Foo<T>::bar b2;
>
> When bar is a type as opposed to a variable? Why can't the compiler
> make that decision?
The typename is only needed inside the definition of a template. When
the compiler processes the template it doesn't know what type is
represented by T (that happens later during instantiation). Consequently
it can't tell of bar is a type or a an object. Consider:
template< typename T >
struct Foo {
typedef int bar;
};
// Specialized version for int.
template<>
struct Foo<int> {
static int bar;
};
In the general template the member bar is a type. However, there is a
specialization for which the member bar is an object. Now consider
Foo<T>::bar. If T is int this refers to an object, otherwise it refers
to a type. When the compiler processes the template that contains
Foo<T>::bar it doesn't know (yet) what it is dealing with and so you
must explicitly tell it. If you include typename, Foo<T>::bar is a type,
otherwise it is an object.
Be aware that in general C++ (and C) can't be parsed without knowing
what identifiers are the names of types. This business with typename
wasn't necessary in old C++ because in old C++ template bodies were not
fully parsed as they were read. They were only parsed at instantiation
time when the nature of the template arguments was known. In modern C++
we have two phase lookup. Non-dependent names in the template bodies are
bound to declarations at the time the template itself is seen. To do
this, the template must be fully parsed before the arguments are known
and this leads to the problem that typename solves.
Hope this helps!
Peter
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: gdr@cs.tamu.edu (Gabriel Dos Reis)
Date: Mon, 17 Jul 2006 02:33:18 GMT Raw View
On Sat, 15 Jul 2006, Peter C. Chapin wrote:
| sashan wrote:
|
| > I'm wondering why the std specifies that typename be used in caseslike
| > this:
| >
| > typename Foo<T>::bar b2;
| >
| > When bar is a type as opposed to a variable? Why can't the compiler
| > make that decision?
|
| The typename is only needed inside the definition of a template. When
| the compiler processes the template it doesn't know what type is
| represented by T (that happens later during instantiation). Consequently
| it can't tell of bar is a type or a an object. Consider:
|
| template< typename T >
| struct Foo {
| typedef int bar;
| };
|
| // Specialized version for int.
| template<>
| struct Foo<int> {
| static int bar;
| };
Yes, but that does not explain why "typename" is needed at the
*parsing time*. The declaration
typename Foo<T>::bar foo;
is invalid for instantiation of Foo with T=int -- assuming your
specializations.
Now, assume the committee decided that Foo<T>::bar -- without the
preceding "typename" -- shall be interpreted as a typename. The above
program with behave the same as if the "typename" was there.
However, not requiring the "typename" means that there is no way to
say
F<T>::B * f;
is actually a multiplication, or that
F<T>::f(x);
is a function call -- remember, C and thereofre C++, allows redundant
parenthesis in declarations.
--
Gabriel Dos Reis
gdr@cs.tamu.edu
Texas A&M University -- Department of Computer Science
301, Bright Building -- College Station, TX 77843-3112
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Gabriel Dos Reis <gdr@cs.tamu.edu>
Date: Mon, 17 Jul 2006 00:58:47 CST Raw View
On Sat, 15 Jul 2006, sashan wrote:
| Hi
|
| I'm wondering why the std specifies that typename be used in cases like
| this:
|
| typename Foo<T>::bar b2;
unfortunate limitation of parsing technology that shrines in the
language specification.
| When bar is a type as opposed to a variable? Why can't the compiler
| make that decision?
Consider the following slightly modified case
Foo<T>::bar * foo;
declaration of pointer "foo" or multiplication?
--
Gabriel Dos Reis
gdr@cs.tamu.edu
Texas A&M University -- Department of Computer Science
301, Bright Building -- College Station, TX 77843-3112
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: gdr@cs.tamu.edu (Gabriel Dos Reis)
Date: Mon, 17 Jul 2006 05:59:11 GMT Raw View
On Sat, 15 Jul 2006, James Dennett wrote:
| sashan wrote:
| > Hi
| >
| > I'm wondering why the std specifies that typename be used in cases like
| > this:
| >
| > typename Foo<T>::bar b2;
| >
| > When bar is a type as opposed to a variable? Why can't the compiler
| > make that decision?
|
| Because, assuming T is a dependent type (i.e., a type depending
| on a template parameter), it's unknowable at the time the template
| is parsed. There may be some T for which Foo<T>::bar is a type,
| and others for which it is an integral constant expression (and
| yet others for which it does not exist, though that's not so
| relevant here).
but even in those disparate cases, using "typename" does nto make the
resulting program valid.
Consider
Foo<T>::bar * foo;
or
Foo<T>::bar(x);
Irrespective of whether the instantiations of Foo<T> may behave as you
said, the parser --before going into instantiation considerations--
still needs clues for deciding whether to parse them as declarations
or expressions-statements.
--
Gabriel Dos Reis
gdr@cs.tamu.edu
Texas A&M University -- Department of Computer Science
301, Bright Building -- College Station, TX 77843-3112
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]