Andrew

May 17, 2007

C++ Templates and Class Inheritance

Filed under: cplusplus,Programming — floodyberry @ 1:03 am
Tags: ,

The following code is not legal C++:

template < class type >
struct A {
	void f() {}
	type mX;
};

template < class type >
struct B : public A<type> {
	void g() { mY = ( mX ); f(); }
	type mY;
};

The best part is that unless you know the obscure reason why it is not legal, it appears legal and might even compile and run perfectly depending on which compiler you’re using. Not surprisingly, that is exactly how I ran in to it. I was doing templated class inheritance and thought I was in the clear because everything ran fine with MSVC7.1 and ICC 9, but when I belatedly tried to compile with g++ 3.4.4, I ran in to the following errors:

tmpl.cpp: In member function `void B<type>::g()’:
tmpl.cpp:9: error: `mX’ undeclared (first use this function)
tmpl.cpp:9: error: (Each undeclared identifier is reported only once for each function it appears in.)
tmpl.cpp:9: error: there are no arguments to `f’ that depend on a template parameter, so a declaration of `f’ must be available
tmpl.cpp:9: error: (if you use `-fpermissive’, G++ will accept your code, but allowing the use of an undeclared name is deprecated)

What the who? Why can’t it find mX or f? How are you supposed to inherit templated classes in g++? Why does it work on some compilers and not others? Is this a bug? The answer is C++ Standards and in this case, gcc 3.4. It didn’t take me long to find a response to this exact same problem on the gcc mailing list from 2004:

re: gcc 3.4 template problem

This happens because gcc 3.4 now implements two-phase name lookup, see http://gcc.gnu.org/gcc-3.4/changes.html and page down until you see the 2nd example in the C++ section, which is much like yours.

Also see DR 213 http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/cwg_defects.html#213 whose resolution adds:

In the definition of a class template or a member of a class template, if a base class of the class template depends on a template-parameter, the base class scope is not examined during unqualified name lookup either at the point of definition of the class template or member or during an instantiation of the class template or member.

to the standard.

You can also use ‘this->x’ to make x dependent, making the implementation to look into the base class.

The C++ FAQ Lite has some further information on the subject with the understandable disclaimer “This might hurt your head; better if you sit down”: [35.19] Why am I getting errors when my template-derived-class uses a member it inherits from its template-base-class?.

While I can understand what the standard is saying and the consequences of it, I can’t figure why some compilers still allow the now illegal behavior (leading to portability nightmares if you don’t know what the heck just broke), and why the intuitive interpretation was made illegal in the first place. Unfortunately, supporting the intuitive version when the standard says the opposite only opens up more opportunities to create non-portable code. While I dislike “this->” litter in my classes, it looks like the cleanest portable solution that doesn’t open up other issues (such as explicit A<type>:: prefixing which would break virtual functions).

If you haven’t had enough, try making sense of this thread in comp.lang.c++.moderated: Dependent names in templates, or are they? What a horrid little rule.

Advertisements

Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com.

%d bloggers like this: