Topic: Nested classes in templates.


Author: "Joerg Schaible" <Joerg.Schaible@no-spam.gft.de>
Date: 1999/04/01
Raw View
Hi Steve,

the original question was "how to define a new type in a template using a
type defined in another template". This is the context where Stroustrup
called typename an annoyance.

template <class _X>
class X
{
    typedef _X XX;
};

template <class _Y = X<_Y> >
class Y
{
    // declare new type just using typename (version of Jerry, his compiler
accepts)
    typename _Y::XX XY_1;
    // declare new type using typedef (the natural way, but some compiler
cannot compile,
    // since they do not know, that _Y::XX is a typedef)
    typedef _Y::XX XY_2;
    // declare new type using typedef and typename (IMHO standard)
    typedef typename _Y::XX XY_3;
};

J   rg
--
BTW: It is normally better to answer to the group! For direct mail reply
remove "no_spam."




[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Bruce Visscher <bvisscher@mindspring.com>
Date: 1999/04/02
Raw View


Steve Clamage wrote:

> [lucid explaination of typename]

What I still have never understood though is why typename is needed in
conjunction with typedef.  I understand that

        T::A * B;

is ambiguous out of context, but what could:

        typedef T::A * B;

possibly mean other than "B is an alias for a pointer to a type T::A" (and so,
T::A must be a type)?

<Pointless Speculation>

I'm tempted to say that had typedef's been allowed to be templatized that the
typename keyword might not have been necessary, but I'm sure I'm overlooking
something.  I.e., keep the rule that a dependent name is assumed not to be a type
but have an exception for typedef.  Then a typedef (rather than typename) could
be used to force names to be types.  There would still be problems with a
dependent name on function returns and function arguments for non-member
functions (since these are introduced at the beginning of template declarations
and so cannot be preceded by a typedef).  Which is where template typedef's come
in:

    template <class T> typedef T::A* APointer;
    template <class T> APointer<T> f();

Of course what I describe isn't C++, I was just wondering if an approach similar
to this was ever discussed (I'm not even sure I like it better...seems like you'd
have an awful lot of typedefs).

</Pointless Speculation>

Regardless of the above, it still seems to be that the sequence ":typedef
typename" should be redundant.

Bruce Visscher



[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Jerry Leichter <leichter@smarts.com>
Date: 1999/04/02
Raw View
| template <class _X>
| class X
| {
|     typedef _X XX;
| };
|
| template <class _Y = X<_Y> >
| class Y
| {
|     // declare new type just using typename (version of Jerry, his
|     // compiler accepts)
|     typename _Y::XX XY_1;

No, no, no!  Please read it - and my previous message on this topic -
again.  This declares a *variable* XY_1 with type _Y::XX.

typename has *nothing* to do with declaring or defining types.  It's a
promise to the compiler that the next qualified name is actually the
name of a type.  The *unit* "typename _Y::XX" is the name of a type.
The "typename" prefix is needed only when the qualified name comes from
a template, where it may not be possible for the compiler to determine
whether the qualified name is a type.  Here's an example:

template <class T>
class C
{ typedef int I;
};

template <class T>
class D
{ C<T>::I* p;
}

This obviously declares p to be a pointer to an int, right?

Well, no.  Suppose we now do:

template <>
class C<float>
{ float I;  // bizarre
};

This is bizarre, but perfectly legal - nothing in C++ requires, much
less enforces, any similarity between a template specialization and the
generic template definition, or between different specializations.
(Similarly, noting in C++ requires, much less enforces, that an over-
riding function in a subclass implements anything that is even slightly
related to the function it overrides.  Obviously, sane programmers keep
things very closely related, except when constructing strange examples!)

Anyhow, now C<float>::I isn't a type - it's a float variable, and the
"declaration" in class D<float> is a multiplication!  This means a C++
compiler couldn't do any meaningful compilation of a template definition
- it couldn't even determine whether it was looking at a declaration or
a statement (often a difficult decision in C++, as it was in C).

If class D had instead been written - as Standard C++ now requires - as:

template <class T>
class D
{ typename C<T>::I* p;
}

then the programmer is explicitly telling the compiler that C<T>::I is
the name of a type.  The compiler then knows that the statement is a
declaration, and after the bizarre specialization, attempting to
construct the specialization D<float> will generate an error.

       -- Jerry
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Jerry Leichter <leichter@smarts.com>
Date: 1999/03/29
Raw View
| >In C++ Primer Plus, it's been mentioned that there is no
| >problems with nesting class definitions in templates, but
| >on both Borland C++ Builder 1.0 and MS VC++ 5.0 I could not
| >get it up and running. In both cases I would get linker
| >errors, indicating that constructor for nested class had
| >not been instaciated.
|
| It's pretty hard to tell whether there is an error in
| your code or a problem in in the compilers. Notice that
| your compilers are not the latest versions, and predate
| the standard.

Nested classes within templates do, indeed, cause problems in MSVC++.
Here's a simple example:

template <class C>
struct f
{       typedef int I;
        I i;
        class g
        {       typename f<C>::I j;             // Fail here
        };
};

f<int> fi;

This fails - I've tested it - in MSVC++ V4.2 and V6.0.  (I don't recall
if 4.2 supported typename; if not, just leave the keyword out.)

While I haven't tested it, I'm told that it fails in MSVC++ V5.0 as
well.

HOWEVER:  I'm told - but can't verify - that MSVC++ V5.0 *with SP3*
successfully compiles similar code.  The fix - if there is one - is not
in SP2 for MSCV++ V6.0.
       -- Jerry


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Joerg Schaible" <Joerg.Schaible@no-spam.gft.de>
Date: 1999/03/30
Raw View
Shouldn't it be coded like:

template <class C>
struct f
{       typedef int I;
        I i;
        class g
        {       typedef typename f<C>::I j;             // Add typedef here
!
        };
};

The typename is just a hint for the compiler, typedef is still necessary

J   rg
--
BTW: It is normally better to answer to the group! For direct mail reply
remove "no_spam."
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Jerry Leichter <leichter@smarts.com>
Date: 1999/03/30
Raw View
| Shouldn't it be coded like:
|
| template <class C>
| struct f
| {       typedef int I;
|         I i;
|         class g
|         {       typedef typename f<C>::I j;       // Add typedef here!
|         };
| };

Either way is valid.  As I posted it, it declared a member j of type int
(after you work through the typedef's.)  As you wrote it, it declares j
to be the type int.

| The typename is just a hint for the compiler, typedef is still
| necessary

typename is not a hint, and has nothing at all to do with typedef.

       -- Jerry


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Joerg Schaible" <Joerg.Schaible@no-spam.gft.de>
Date: 1999/03/31
Raw View
Hi Jerry,

>Either way is valid.
>typename is not a hint, and has nothing at all to do with typedef.

Stroutrup himself defines the "typename" as annoyance (see 16.3.1, 3rd ed.),
since the compiler is not able to distinct for template paremeters between
variables and names. I did not found anywhere typename to be a "replacement"
for typedef, if you define a type within a class, you have to use typedef.
If the compiler could not know that your template parameter you use for the
definition is a type, you have to add "typename". If some compiler vendors
allow to omit one of the key words, OK, but is it standard?

J   rg
--
BTW: It is normally better to answer to the group! For direct mail reply
remove "no_spam."
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: clamage@eng.sun.com (Steve Clamage)
Date: 1999/03/31
Raw View
"Joerg Schaible" <Joerg.Schaible@no-spam.gft.de> writes:

>>Either way is valid.
>>typename is not a hint, and has nothing at all to do with typedef.

>Stroutrup himself defines the "typename" as annoyance (see 16.3.1, 3rd ed.),
>since the compiler is not able to distinct for template paremeters between
>variables and names. I did not found anywhere typename to be a "replacement"
>for typedef, if you define a type within a class, you have to use typedef.
>If the compiler could not know that your template parameter you use for the
>definition is a type, you have to add "typename". If some compiler vendors
>allow to omit one of the key words, OK, but is it standard?

The keywords "typename" and "typedef" have distinct and unrelated
purposes.  Neither one is a hint to the compiler.  Each has a
specific syntactic and semantic role in standard C++.

The keyword typedef defines a name to be an alias in the current
scope for a previously-declared type.

The keyword typename in a template definition is a name qualifier
that specifies that a name dependent on a template parameter is the
name of some as-yet unspecified type.  It does not declare or define
the name, nor does it declare or define the type.

In standard C++, if a dependent name in a template definition is not
qualified with "typename", the name is assumed NOT to be the name of
a type. Not all compilers enforce that rule (yet).

Originally, C++ did not have the keyword typename. Without knowing
whether a name is a type, a template definition cannot be parsed
until it is instantiated. Example, where T is a template parameter:
 T::A * B;
If T::A is a type, the line declares B to be a pointer; otherwise
it multiplies T::A by B (perhaps for the side effect of an
overloaded operator). Consequently, compilers could not do
anything with a template definition until it was instantiated.
If the line was in error, you would then get the same error message
on every instantiation.

To allow better error handling and reporting, the "typename"
requirement was added. A compiler can now sometimes determine that
a construct cannot be valid for any instantiation, issue the error
message for the template definition, and not attempt any
instantiations.

Once "typename" was added to C++, it made sense to allow it to
be used in declaring template parameters. The keyword "class" in
 template<class T> ...
seems like over-specification when T need not be a class type.
 template<typename T> ...
is an alternative, more expressive, declaration syntax.

--
Steve Clamage, stephen.clamage@sun.com
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Ivan Strougatski <tpkec@wmin.ac.uk>
Date: 1999/03/22
Raw View
In C++ Primer Plus, it's been mentioned that there is no
problems with nesting class definitions in templates, but
on both Borland C++ Builder 1.0 and MS VC++ 5.0 I could not
get it up and running. In both cases I would get linker
errors, indicating that constructor for nested class had
not been instaciated.
Also, are the any plans to introduce co-variance into C++ as
templates are not always the best solution?


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Stephen.Clamage@Eng.Sun.COM (Steve Clamage)
Date: 1999/03/23
Raw View
Ivan Strougatski <tpkec@wmin.ac.uk> writes:

>In C++ Primer Plus, it's been mentioned that there is no
>problems with nesting class definitions in templates, but
>on both Borland C++ Builder 1.0 and MS VC++ 5.0 I could not
>get it up and running. In both cases I would get linker
>errors, indicating that constructor for nested class had
>not been instaciated.

It's pretty hard to tell whether there is an error in
your code or a problem in in the compilers. Notice that
your compilers are not the latest versions, and predate
the standard.

>Also, are the any plans to introduce co-variance into C++ as
>templates are not always the best solution?

Covariant return types on virtual functions are part
of standard C++.

--
Steve Clamage, stephen.clamage@sun.com
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]