C ++继承自未定义的模板类型

时间:2011-06-13 13:55:30

标签: c++ templates inheritance gcc

此代码:

template <class T>
class Foo {};

typedef Foo<void*> Bar;

template <class T>
class Foo<T*> : public Bar {};

// use Foo<int*> somewhere.

在MSVC 9.0中编译并正常工作,但不能在GCC 4.1.1或GCC 4.3.4中编译,错误:

error: invalid use of undefined type 'class Bar'

这是非法的C ++ MSVC接受错误,还是GCC的限制?

无论哪种方式,我如何解决这个问题,获得所需的行为:从Foo继承的Foo<void*>指针特化?

3 个答案:

答案 0 :(得分:5)

除非T*T,否则除了为所有void编写专门化外,您不能这样做。否则,您将从自身派生类,由于显而易见的原因无法工作。

无法为具有显式或部分特化的参数实例化主类模板。如果你尝试通过在显式或部分特化之前激发实例化(注意你的代码没有激发这样的实例化),你的程序就会形成错误,不需要诊断(这有效地使行为未定义)

要实现上述解决方法,您可以使用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*> {};

答案 1 :(得分:3)

typedef是红鲱鱼。

以下代码是等效的:

template <class T>
class Foo {};

template <class T>
class Foo<T*> : public Foo<void*> {};

应该很清楚,虽然此时声明了Foo<T*>,但它没有定义。因此,您不能将其用作基础。


[class.name](2003年措辞,9.1 / 2):

  

类定义将类名引入定义它的范围

[class.mem](2003年措辞,9.2 / 2):

  

一个班级被认为是一个   完全定义的对象类型(3.9)   (或完成类型)在结束时   类说明符。在课堂上   成员规范,类是   在功能内被视为完整   主体,默认参数和   构造函数ctor-initializers   (包括嵌套的这类东西   类)。 否则被视为   在自己的班级内不完整   构件规格。

[class.derived](2003年措辞,10/1):

  

基本说明符中的类名不应是未完全定义的类(第9条);

答案 2 :(得分:0)

卓越的解决方案是撰写Foo<void*>。毕竟,您不希望原始void*界面混乱您的内容,并且您希望Foo<T*>可以转换为Foo<void*>

或者,您可以事先完全专门化Foo<void*>

当然,假设您正在为类型折叠执行此操作,而不是因为您实际上想要继承。