在这篇文章中,我试图在B类中声明一个列表,该列表可以保存任何类型的A类对象,例如A< int>,A< double>,A< float>。我打算在运行时将A对象添加到列表中:
#include <list>
template <class T> class A {};
class B {
template<class T> std::list<A<T>*> objects;
};
看起来像这样的列表应该可以工作但是编译它会产生错误:
第6行:错误:数据成员'对象'不能是成员模板
由于-Wfatal-errors而导致编译终止。
有人可以解释为什么这不起作用以及如何解决它?
答案 0 :(得分:14)
这不是C ++的工作方式。如果要将不同的对象组合在一起,则它们至少需要某些关系。作为同一类模板的实例化并不意味着它们是相关的,它们是完全不同的类型。如果你想要一个A<T>*
的列表,最好通过虚函数制作一个基类指针和转发操作的列表:
class A_base{
public:
virtual void foo() = 0;
virtual ~A_base() { }
};
template<class T>
class A : public A_base{
public:
void foo(){
// ...
}
};
class B{
std::list<A_base*> objects;
};
答案 1 :(得分:5)
不允许成员变量为模板。只有成员功能可以是模板。您将不得不将封闭的类B
模板化:
template <class T>
class B {
std::list<A<T>*> objects;
};
答案 2 :(得分:3)
不幸的是,您无法拥有模板变量。只有声明成员数据的选项才能生成类模板:
template<class T>
class B {
std::list<A<T>*> objects;
};
答案 3 :(得分:2)
根据您的操作,可能会选择类型擦除。 On the Tension Between Object-Oriented and Generic Programming in C++是我最喜欢的关于这个主题的文章。
简而言之,您可以通过动态设置的自定义继承树将模板启用的静态分派转换为动态分派。您不是存储A<T>
,而是创建一个具有所需公共接口的新类型,并使用一些模板/不一致voodoo,这种新类型存储A<T>
而不实际暴露T
。因此,A<int>
和A<double>
以及A<A<std::list<A<int> > > >
和some_type_that_looks_like_A_but_really_isnt
都会缩减为单一类型。
但是你必须有一个共同的界面,独立于那个参数。如果你做不到,事情会变得更加困难。
Boost.Any是一个很好的例子,就像std::shared_ptr
[使用类型擦除来记住如何删除传递给它的指针,即使面对非多态继承]。
答案 4 :(得分:0)
制作B
课程模板,就像您已将A
作为课程模板一样:
template<class T>
class B {
std::list<A<T>*> objects;
};