Prev: Tree container library
Next: Atexit() and C++
From: mikehcox on 25 Jan 2006 09:48 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 25 Jan 2006 15:19 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 25 Jan 2006 15:51 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 26 Jan 2006 07:27 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 26 Jan 2006 07:50
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! ] |