This code:
template <class T>
class Foo {};
typedef Foo<void*> Bar;
template <class T>
class Foo<T*> : public Bar {};
// use Foo<int*> somewhere.
Compiles and works fine in MSVC 9.0, but doesn't compile in GCC 4.1.1 or GCC 4.3.4, with the error:
error: invalid use of undefined type 'class Bar'
Is this illegal C++ that MSVC accepts incorrectly, or a limitation of GCC?
Either way, how can I work around this get the desired behaviour: pointer specialisations of Foo
that inherit from unspecialised Foo<void*>
?
You cannot do that, except by writing the specialization for all T*
, except when T
is void
. Otherwise, you will derive the class from itself, which for obvious reasons can't work.
Instantiating the primary class template for arguments that have an explicit or partial specialization is not possible. If you try to, by provoking an instantiation before the explicit or partial specialization is visible (note that your code did not provoke such an instantiation), your program is ill-formed, with no diagnostic being required (which effectively renders the behavior undefined).
To achieve the above work-around, you can use SFINAE
template <class T>
struct isnt_void { typedef void type; };
template<> struct isnt_void<void> { };
template <class T, class = void>
class Foo {};
template <class T>
class Foo<T*, typename isnt_void<T>::type> : public Foo<void*> {};
The typedef
is a red herring.
The following code is equivalent:
template <class T>
class Foo {};
template <class T>
class Foo<T*> : public Foo<void*> {};
It should be clear that, although Foo<T*>
is declared at this point, it is not defined. And thus you may not use it as a base.
[class.name]
(2003 wording, 9.1/2):
A class definition introduces the class name into the scope where it is defined
[class.mem]
(2003 wording, 9.2/2):
A class is considered a completely-defined object type (3.9) (or complete type) at the closing } of the class-specifier. Within the class member-specification, the class is regarded as complete within function bodies, default arguments and constructor ctor-initializers (including such things in nested classes). Otherwise it is regarded as incomplete within its own class member-specification.
[class.derived]
(2003 wording, 10/1):
The class-name in a base-specifier shall not be an incompletely defined class (clause 9);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With