此代码:
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*>
指针特化?
答案 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*>
。
当然,假设您正在为类型折叠执行此操作,而不是因为您实际上想要继承。