Thread: gcc: Template class child can't directly access parent fields

  1. #1
    Registered User
    Join Date
    Apr 2007
    Posts
    141

    gcc: Template class child can't directly access parent fields

    OK this has to be a bug in gcc 4.3. At the very least the error reporting should be considered a bug since it starts spewing unreadable characters.

    Normally a child class can access the fields of a parent class as though they were her own. Not so in gcc 4.3 if the class is templated. You need to use the this pointer indirection to get at them.

    Code:
    #include <iostream>
    
    template<int i>
    class A
    {
    	public:
    	int f ; // a field
    } ;
    
    
    template<int i>
    class B : public A<i>
    {
    	public:
    	B()
    	{
    		f = 2 ;
    	}
    } ;
    
    
    int main(int argc, char *argv[])
    {
    B<0>  bc ;
    std::cout << bc.f << std::endl ;
    
    }
    This compiles and runs fine in MS Vis. studio. On linux, for gcc 4.3.0, it gives this 'informative' error

    child.cpp: In constructor â:
    child.cpp:15: error: â was not declared in this scope

    In the constructor if you replace f by this->f it will compile.

  2. #2
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    This is due to two-phase name lookup. The gcc compiler is correct, and MSVC is wrong to compile it. As far as the weird characters in the error message, I have no idea.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  3. #3
    Registered User
    Join Date
    Apr 2007
    Posts
    141
    Quote Originally Posted by brewbuck View Post
    This is due to two-phase name lookup. The gcc compiler is correct, and MSVC is wrong to compile it. As far as the weird characters in the error message, I have no idea.
    I've read a similar phrase somewhere else. Care to elaborate? Is this something the standard specifies with regards to how things are compiled?

  4. #4
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by SevenThunders View Post
    I've read a similar phrase somewhere else. Care to elaborate? Is this something the standard specifies with regards to how things are compiled?
    The compiler should not assume that f is a member of the parent class. There is no way of knowing whether, at the time of instantiation of B<>, whether there has been a specialization of A<> which does not include this member.

    If the compiler blindly allowed it, you might have a situation where the reference to f is referring to a parent member in one case, and some completely different object (for instance a global variable) in some other case. It's safer to force you to be explicit about it.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  5. #5
    Registered User
    Join Date
    Apr 2007
    Posts
    141
    OK I'll answer my own question with this link, which even explains two-phase name lookup.
    http://womble.decadentplace.org.uk/c...ml#base-lookup

    Seems a bit complex. How is it a great idea like templates, becomes filled with unnecessary complexity and hazards when implemented in C++?

  6. #6
    Registered User
    Join Date
    Apr 2007
    Posts
    141
    Quote Originally Posted by brewbuck View Post
    The compiler should not assume that f is a member of the parent class. There is no way of knowing whether, at the time of instantiation of B<>, whether there has been a specialization of A<> which does not include this member.

    If the compiler blindly allowed it, you might have a situation where the reference to f is referring to a parent member in one case, and some completely different object (for instance a global variable) in some other case. It's safer to force you to be explicit about it.
    Why not simply check the available possible resolutions for f, and only report the error if such an ambiguity arises? That would be a more liberal compiler protocol and give us perfectly reasonable results.

    A programmer doesn't want to have to keep track of all possible compiler semantics. ie I have to remember half way in the middle of a huge template, that I'm accessing a parent field instead of a child field. Isn't that the reason why we have such wonderful things as function overloading and templates to begin with?

    Oh well, just another glitch in my love hate relationship with C++.

  7. #7
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by SevenThunders View Post
    Why not simply check the available possible resolutions for f, and only report the error if such an ambiguity arises? That would be a more liberal compiler protocol and give us perfectly reasonable results.
    Do you really want your code to suddenly become wrong just because somebody declares a global variable named 'f'?

    To me, going from "compiles" to "doesn't compile" based on whether I declare a variable doesn't make much sense.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  8. #8
    Registered User
    Join Date
    Apr 2007
    Posts
    141
    Quote Originally Posted by brewbuck View Post
    Do you really want your code to suddenly become wrong just because somebody declares a global variable named 'f'?

    To me, going from "compiles" to "doesn't compile" based on whether I declare a variable doesn't make much sense.
    I cant seem to get that to happen via MS VC which does compile with references to the parent class variables.

    Maybe I did something wrong.

    Code:
    #include <iostream>
    
    
    template<int i>
    class A
    {
    	public:
    		int f ;
    		void print()
    		{
    			std::cout << f << std::endl ;
    		}
    } ;
    
    
    template<int i>
    class B : public A<i>
    {
    	public:
    		B()
    		{
    //			f = i ;
    		}
    } ;
    
    
    
    int f = 2 ;
    
    int main(int argc, char *argv[])
    {
    
    	B<7> aa ;
    	aa.print() ;
    }

  9. #9
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    You have no specialization of A<> which does not contain f. And given MSVC's proven inability to handle this construct properly, I'm not sure it's a good test bed.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  10. #10
    The larch
    Join Date
    May 2006
    Posts
    3,573
    In this case it would switch to using the global f (or it that is removed, error out when instantiating a B, whose A doesn't have the f member).

    Code:
    #include <iostream>
    
    template<int i>
    class A
    {
    	public:
    		int f ;
    		void print()
    		{
    			std::cout << f << std::endl ;
    		}
    } ;
    
    template<int i>
    class B : public A<i>
    {
    	public:
    		B()
    		{
    			f = i ;
    		}
    } ;
    
    template <>
    class A<8>
    {
        public:
        void print()
        {
            std::cout << "no f" << std::endl;
        }
    };
    
    int f = 2 ;
    
    int main()
    {
    
    	B<8> aa ;
    	aa.print() ;
    	std::cout << "global f " << f << '\n';
    }
    GCC would always go for the global f (if it is declared before the classes) and won't change the meaning of code based on which specializations are available (f refers to one thing or nothing at all).

    Has it been mentioned that the simple workaround to accessing members of the template parent is to use the this pointer:

    Code:
    B()
    {
         this->f = i ;
    }
    Even MSVC can't argue with this and just plug in any f it happens to find.
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  11. #11
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Templates also, unfortunately, add a lot of complexity into the language. Asking compiler vendors to be able to handle all of this stuff without programmer interaction is just not plausible.
    It's hard enough already to write a C++ compiler, and the standard has to make sure it isn't impossible.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  12. #12
    The larch
    Join Date
    May 2006
    Posts
    3,573
    The problem with VC++ implementation is that it is possible to have the meaning of a piece of code completely changed from the outside. Here the same piece of code can be made to use a global variable without modifying itself (class B). It is probably related to how it doesn't require the typename keyword in case of dependent types. Again it is possible that an identifier within the same piece of code can be both a type or a variable name, depending on the context outside that code. (While the programmer has to type less, having a compiler guess what might be meant doesn't seem in the spirit of C++.)
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Access data in a parent class.
    By Queatrix in forum C++ Programming
    Replies: 24
    Last Post: 09-17-2006, 04:02 PM
  2. Dikumud
    By maxorator in forum C++ Programming
    Replies: 1
    Last Post: 10-01-2005, 06:39 AM
  3. Tab Controls - API
    By -KEN- in forum Windows Programming
    Replies: 7
    Last Post: 06-02-2002, 09:44 AM
  4. Linked list with two class types within template.
    By SilasP in forum C++ Programming
    Replies: 3
    Last Post: 02-09-2002, 06:13 AM
  5. oh me oh my hash maps up the wazoo
    By DarkDays in forum C++ Programming
    Replies: 5
    Last Post: 11-30-2001, 12:54 PM