From: mikehcox on
Below is a file I'm getting compile errors on (CASEs 1 and 2). I think
both 1 and 2 should be legal C++. Visual C++ Expres 2005 agrees with
me. Compiling using Cygwin's GNU 3.4.4 has the shown error messages.
Which compiler is right and what C++ standard clause would cover this
situation?

Thanks,
Mike

template<typename T>
class typedef_class
{
public:
typedef T nested_type;
};

template<typename Derived, typename TypedefClass>
class base_nested_typedef
{
public:
typedef typename TypedefClass::nested_type nested_type;
};

template<typename Derived, typename TypedefClass>
class derived_nested_typedef:
public base_nested_typedef<Derived, TypedefClass>
{
public:
derived_nested_typedef();

#if CASE==1
derived_nested_typedef(nested_type);
#elif CASE==2
void foo(nested_type);
#elif CASE==3
typedef typename base_nested_typedef<Derived,
TypedefClass>::nested_type
nested_type;

derived_nested_typedef(nested_type);
void foo(nested_type);
#endif
};


class derived2: public derived_nested_typedef<derived2,
typedef_class<int> >
{
public:
};

derived2::nested_type data;

/*
When I compile the above code, I get the following error messages for
CASE==1
and CASE==2, respectively:

CASE==1:
$ g++ -c -DCASE=1 nested_typedef.cc
nested_typedef.cc: In instantiation of
`derived_nested_typedef<derived2, typedef_class<int> >':
nested_typedef.cc:37: instantiated from here
nested_typedef.cc:23: error: `derived_nested_typedef<Derived,
TypedefClass>::nested_type' has incomplete type
nested_typedef.cc:18: error: declaration of `class
derived_nested_typedef<derive
d2, typedef_class<int> >'

CASE==2
$ g++ -c -DCASE=2 nested_typedef.cc
nested_typedef.cc:25: error: `nested_type' has not been declared
nested_typedef.cc:25: error: ISO C++ forbids declaration of `parameter'
with no type

CASE==3
$ g++ -c -DCASE=3 nested_typedef.cc

Why isn't the base class nested typedef, nested_type, being recognized
in case
1 or 2? Why does it compile when I add the typedef on line 27? Is
this a
bug in the compiler or my understanding of the visibility of nested
typedefs?

The version of g++ is
$ g++ --version
g++ (GCC) 3.4.4 (cygming special) (gdc 0.12, using dmd 0.125)
Copyright (C) 2004 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is
NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.

Visual C++ Express 2005 compiles this fine.
*/


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Axter on
mikehcox(a)gmail.com wrote:
> Below is a file I'm getting compile errors on (CASEs 1 and 2). I think
> both 1 and 2 should be legal C++. Visual C++ Expres 2005 agrees with
> me. Compiling using Cygwin's GNU 3.4.4 has the shown error messages.
> Which compiler is right and what C++ standard clause would cover this
> situation?
>
> Thanks,
> Mike
>
> template<typename T>
> class typedef_class
> {
> public:
> typedef T nested_type;
> };
>
> template<typename Derived, typename TypedefClass>
> class base_nested_typedef
> {
> public:
> typedef typename TypedefClass::nested_type nested_type;
> };
>
Try using the following syntax:

template<typename Derived, typename TypedefClass>
class base_nested_typedef
{
public:
typedef typename TypedefClass::template nested_type nested_type;
};

Notice the keyword template after TypedefClass::
This is required.
VC++ is much more forgiving.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Thomas Tutone on

mikehcox(a)gmail.com wrote:
> Below is a file I'm getting compile errors on (CASEs 1 and 2). I think
> both 1 and 2 should be legal C++. Visual C++ Expres 2005 agrees with
> me. Compiling using Cygwin's GNU 3.4.4 has the shown error messages.
> Which compiler is right and what C++ standard clause would cover this
> situation?

Comeau online (which is what I always check when I have questions like
this) agrees with gcc, so I'm voting with gcc on this one.

Best regards,

Tom


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: mikehcox on
I tried adding the template keyword. It made things worse,
unfortunately. Now I get this:

template<typename T>
class typedef_class
{
public:
typedef T nested_type;
};

template<typename Derived, typename TypedefClass>
class base_nested_typedef
{
public:
typedef typename TypedefClass::template nested_type nested_type;
};

template<typename Derived, typename TypedefClass>
class derived_nested_typedef:
public base_nested_typedef<Derived, TypedefClass>
{
public:
derived_nested_typedef();

#if CASE==1
derived_nested_typedef(nested_type);
#elif CASE==2
void foo(nested_type);
#elif CASE==3
typedef typename base_nested_typedef<Derived,
TypedefClass>::nested_type
nested_type;

derived_nested_typedef(nested_type);
void foo(nested_type);
#endif
};


class derived2: public derived_nested_typedef<derived2,
typedef_class<int> >
{
public:
};

derived2::nested_type data;

/*
When I compile the above code, I get the following error messages for
CASE==1
and CASE==2, respectively:

CASE=1:
$ g++ -c -DCASE=1 nested_typedef.cc
nested_typedef.cc:12: error: expected template-id before "nested_type"
nested_typedef.cc:12: error: `nested_type' does not name a type
nested_typedef.cc: In instantiation of
`derived_nested_typedef<derived2, typedef
_class<int> >':
nested_typedef.cc:37: instantiated from here
nested_typedef.cc:23: error: `derived_nested_typedef<Derived,
TypedefClass>::nes
ted_type' has incomplete type
nested_typedef.cc:18: error: declaration of `class
derived_nested_typedef<derive
d2, typedef_class<int> >'
nested_typedef.cc:41: error: expected constructor, destructor, or type
conversio
n before "data"
nested_typedef.cc:41: error: expected `,' or `;' before "data"

CASE=2:
$ g++ -c -DCASE=2 nested_typedef.cc
nested_typedef.cc:12: error: expected template-id before "nested_type"
nested_typedef.cc:12: error: `nested_type' does not name a type
nested_typedef.cc:25: error: `nested_type' has not been declared
nested_typedef.cc:25: error: ISO C++ forbids declaration of `parameter'
with no
type
nested_typedef.cc:41: error: expected constructor, destructor, or type
conversio
n before "data"
nested_typedef.cc:41: error: expected `,' or `;' before "data"

CASE=3:
$ g++ -c -DCASE=3 nested_typedef.cc
nested_typedef.cc:12: error: expected template-id before "nested_type"
nested_typedef.cc:12: error: `nested_type' does not name a type
nested_typedef.cc: In instantiation of
`derived_nested_typedef<derived2, typedef
_class<int> >':
nested_typedef.cc:37: instantiated from here
nested_typedef.cc:28: error: no type named `nested_type' in `class
base_nested_t
ypedef<derived2, typedef_class<int> >'
nested_typedef.cc:30: error: no type named `nested_type' in `class
base_nested_t
ypedef<derived2, typedef_class<int> >'
nested_typedef.cc:31: error: no type named `nested_type' in `class
base_nested_t
ypedef<derived2, typedef_class<int> >'
nested_typedef.cc:41: error: expected constructor, destructor, or type
conversio
n before "data"
nested_typedef.cc:41: error: expected `,' or `;' before "data"


Why isn't the base class nested typedef, nested_type, being recognized
in case
1 or 2? Why does it compile when I add the typedef on line 27? Is
this a
bug in the compiler or my understanding of the visibility of nested
typedefs?

The version of g++ is
$ g++ --version
g++ (GCC) 3.4.4 (cygming special) (gdc 0.12, using dmd 0.125)
Copyright (C) 2004 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is
NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.
*/



Axter wrote:
> mikehcox(a)gmail.com wrote:
> > Below is a file I'm getting compile errors on (CASEs 1 and 2). I think
> > both 1 and 2 should be legal C++. Visual C++ Expres 2005 agrees with
> > me. Compiling using Cygwin's GNU 3.4.4 has the shown error messages.
> > Which compiler is right and what C++ standard clause would cover this
> > situation?
> >
> > Thanks,
> > Mike
> >
> > template<typename T>
> > class typedef_class
> > {
> > public:
> > typedef T nested_type;
> > };
> >
> > template<typename Derived, typename TypedefClass>
> > class base_nested_typedef
> > {
> > public:
> > typedef typename TypedefClass::nested_type nested_type;
> > };
> >
> Try using the following syntax:
>
> template<typename Derived, typename TypedefClass>
> class base_nested_typedef
> {
> public:
> typedef typename TypedefClass::template nested_type nested_type;
> };
>
> Notice the keyword template after TypedefClass::
> This is required.
> VC++ is much more forgiving.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: kanze on
mikehcox(a)gmail.com wrote:

> Below is a file I'm getting compile errors on (CASEs 1 and 2).
> I think both 1 and 2 should be legal C++. Visual C++ Expres
> 2005 agrees with me. Compiling using Cygwin's GNU 3.4.4 has
> the shown error messages. Which compiler is right and what C++
> standard clause would cover this situation?

This looks like a fairly standard two phase lookup issue. Given
two phase lookup, I don't see how 1 or 2 could possibly compile.

> template<typename T>
> class typedef_class
> {
> public:
> typedef T nested_type;
> };

> template<typename Derived, typename TypedefClass>
> class base_nested_typedef
> {
> public:
> typedef typename TypedefClass::nested_type nested_type;
> };

> template<typename Derived, typename TypedefClass>
> class derived_nested_typedef:
> public base_nested_typedef<Derived, TypedefClass>
> {
> public:
> derived_nested_typedef();
>
> #if CASE==1
> derived_nested_typedef(nested_type);
> #elif CASE==2
> void foo(nested_type);

What's nested_type here? The context doesn't even tell the
compiler that it is dependent, so the compiler must be able to
find it without instantiating the template. Since there is no
nested_type in this context, the code is in error. Note
particularly ?14.6.2/3 "In the definition of a class template
[...], if a base class of this template depends on a
template-paramter, the base class scope is not examined during
name lookup until the class tmeplate is instantiated."

Off hand, I don't see anything which would change this reasoning
in CASE==1. G++ gives a significantly different error message,
but as far as I can see, the only context where a non-qualified
name can be dependent is in an expression or the specification
of a compound type (or if the name itself is a template
parameter, of course). I would expect exactly the same error
message in CASE==1 as you got here: nested_type has not been
declared.

> #elif CASE==3
> typedef typename base_nested_typedef<Derived,
> TypedefClass>::nested_type
> nested_type;

No problem here: the qualification ensures that the first use of
nested_type is dependent. (This means, of course, that the
typename is necessary.)

Note that you don't need the typedef. Just write the equivalent
out fully in all of the cases where you use nested_type.

> derived_nested_typedef(nested_type);
> void foo(nested_type);
> #endif
> };

> class derived2: public derived_nested_typedef<derived2,
> typedef_class<int> >
> {
> public:
> };

> derived2::nested_type data;

> /*
> When I compile the above code, I get the following error messages for
> CASE==1
> and CASE==2, respectively:

> CASE==1:
> $ g++ -c -DCASE=1 nested_typedef.cc
> nested_typedef.cc: In instantiation of
> `derived_nested_typedef<derived2, typedef_class<int> >':
> nested_typedef.cc:37: instantiated from here
> nested_typedef.cc:23: error: `derived_nested_typedef<Derived,
> TypedefClass>::nested_type' has incomplete type
> nested_typedef.cc:18: error: declaration of `class
> derived_nested_typedef<derive
> d2, typedef_class<int> >'

> CASE==2
> $ g++ -c -DCASE=2 nested_typedef.cc
> nested_typedef.cc:25: error: `nested_type' has not been declared
> nested_typedef.cc:25: error: ISO C++ forbids declaration of `parameter'
> with no type

> CASE==3
> $ g++ -c -DCASE=3 nested_typedef.cc

> Why isn't the base class nested typedef, nested_type, being
> recognized in case 1 or 2?

Because the base class is a dependent type, and you've used the
name nested_type in non-dependent contexts, where the name will
be bound before the template is ever instantiated, and the
compiler will not take the dependent base class into
consideration when looking up the name.

> Why does it compile when I add the typedef on line 27?

Because the C++ declaration syntax is based on C, and the C
declaration syntax is "an experiment which failed". (I don't
know who first said that, but it expresses the situation
nicely.)

Seriously: in order to correctly parse C++, you must know which
names are typenames, and which ones aren't. The standard goes
out of its way to allow compilers to parse templates before they
are instantiated, in order to detect errors as early as
possible. In the case of dependent names, it says (?14.6/2-3) "A
name used in a template declaration or definition and that is
dependent on a template-parameter is assumed not to name a type
unless the applicable name lookup finds a type name or the name
is qualified by the keyword typename. ? A qualified-name that
refers to a type and that depends on a template-parameter shall
be prefixed by the keyword typename to indicate that the
qualified-name denotes a type, forming an
elaborated-type-specifier."

> Is this a bug in the compiler or my understanding of the
> visibility of nested typedefs?

Certainly not a bug in the compiler (except maybe for the actual
error message in case 1); some people do consider it a bug in
the standard:-). Globally, however, I think you're having
problems with understanding the way two phased lookup works.
And what is and is not a dependent name. (It's not always
evident, but in this case, I don't find it particularly
obscure.) The important thing to realize, here, is that the
compiler does NOT look into a dependent base class during
non-dependent name lookup; the reason for this is simple: until
it actually instantiates the template, it cannot know whether
there will be a specialization of the base class for the
particular types or not.

> The version of g++ is
> $ g++ --version
> g++ (GCC) 3.4.4 (cygming special) (gdc 0.12, using dmd 0.125)
> Copyright (C) 2004 Free Software Foundation, Inc.
> This is free software; see the source for copying conditions. There is
> NO
> warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
> PURPOSE.

4.0.2 gives the same error messages.

> Visual C++ Express 2005 compiles this fine.
> */

According to the standard, it shouldn't. Practically, there are
backward compatibility issues to be considered, and a good
compiler will try to provide a migration path. Regretfully, all
too often, the "migration path" is activated by default (rather
than requiring a special compiler option), and doesn't even give
a warning.

G++ accepted this in pre-3.0. I'm not sure, but I think that
they gave a warning in versions 3.0--3.3.n, and only made it an
error in 3.4. Ideally, we'd like an option to reduce it to a
warning, or even to turn the warning off, but I suspect that
providing such an option would be a lot of work.

I can very well understand a compiler not generating an error
for this, but IMHO, in 2005, a compiler should at least generate
a warning.

--
James Kanze GABI Software
Conseils en informatique orient?e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S?mard, 78210 St.-Cyr-l'?cole, France, +33 (0)1 30 23 00 34


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

 |  Next  |  Last
Pages: 1 2
Prev: Tree container library
Next: Atexit() and C++