[LC++]Why new behaviour of g++?

Torsten Rennett Torsten at Rennett.de
Tue Feb 22 21:56:02 UTC 2005


On Mittwoch, 16. Februar 2005 09:17, Dr Mark H Phillips wrote:
> The recent versions of g++ (in contrast to 3.3.* versions) will no
> longer compile:
>
>   #include <iostream>
>
>   template<typename T> struct SixStore {
>     int store; SixStore(): store(6) {}
>   };
>
>   template<typename T> struct Six: public SixStore<T> {
>     int six() {return store;}
>   };
>
>   int main() {
>     Six<char> s;
>     std::cout<<"six = "<<s.six()<<std::endl;
>   }
>
> It complains with:
>
>   tst3.cc: In member function `int Six<T>::six()':
>   tst3.cc:8: error: `store' undeclared (first use this function)

Due to the latest C++ Standard, nondependent names (here: store) are
*not* looked up in dependent base classes (here: base class SixStore
depends on template parameter T of class Six).

> If I remove the template stuff however, it compiles fine.

It also works with the template stuff, if you change the nondependent
name into a dependent one :-)  You have 2 possibilities to make 'store'
depend on 'T':

  1st solution:
	template<typename T> struct Six : public SixStore<T>
	{
	  int six() { return this->store; }
	};

  2nd solution:
	template<typename T> struct Six : public SixStore<T>
	{
	  int six() { return SixStore<T>::store; }
	};

But be aware, in the case 'store' is not a data member but a member
function (method), that the 2nd solution disables all virtual call
mechanism!


> I had a look on the GCC website and on the page
>
>   http://gcc.gnu.org/bugs.html#known
>
> I found the following information:
>
>   This also affects members of base classes, see [14.6.2]:
>                 template <typename> struct A
>                 {
>                     int i, j;
>                 };
>
>                 template <typename T> struct B : A<T>
>                 {
>                     int foo1() { return i; }       // error
>                     int foo2() { return this->i; } // OK
>                     int foo3() { return B<T>::i; } // OK
>                     int foo4() { return A<T>::i; } // OK
>
>                     using A<T>::j;
>                     int foo5() { return j; }       // OK
>                 };
>
> and foo1() seems to be pretty much what I was unsuccessfully trying to
> do!

Yep, that's right!

> But why does g++ now outlaw this?  

Suppose you have the following slightly modified code:

    template<typename T> struct SixStore 
    {
      int store;
      SixStore() : store(6) {}
    };

    template<typename T> struct Six : public SixStore<T>
    {
      void setStore(int val) { store = val; }	// point (1)
    };

    template<>              // explicit specialization
    struct SixStore<bool>
    {
      enum { store = 1 };			// point (2)
    };

    int main()
    {
      Six<bool> s;
      s.setStore(100);				// point (3)
    }


If the nondependent name ('store') would be looked up at point (1), it
would be bind to the int member of class SixStore.  After this we
declare an explicit specialization of class SixStore for the type bool,
which unfortunately changes the meaning of 'store' (point 2) -- 'store'
is no longer modifiable!  Finally we create an instance of Six<bool> at
point (3). At this point the explicit specialization is known and causes
a conflict, since we have bound 'store' too early at point (1).

To solve this conflict, the C++ Standard says that nondependent names
are *not* looked up in dependent base classes.  So a standard conforming
C++ compiler has to emit an error at point (1) -- and this is what gcc
does :-)

If we modify the code like shown above (1st + 2nd solution), the binding
will be delayed.  The dependent name can be looked up only at the time
of instantiation and at that time the exact base specialization will be
known -- and 'store' will bind correctly to the enum 'store' in class
SixStore<bool>.  This time the compiler will emit an error at point (3),
since setStore() can not modify an enum!

HTH,
Torsten

-- 
Ingenieurbuero RENNETT      -- innovative Software-Entwicklung --
Torsten Rennett                    http://www.RENNETT.de
Ludwig-Thoma-Weg 14         E-Mail:            Torsten at Rennett.de
D-85551 Heimstetten         Telefon:            +49 89 904 805 38




More information about the tuxCPProgramming mailing list