我想知道你是否可以拥有一个包含不同模板参数的对象的容器。
我试图达到这样的目标:
#include <iostream>
#include <list>
template <class T>
class base
{
public:
T val;
base(T newVal): val(newVal) {};
};
class derived : public base<int>
{
public:
derived(int newVal): base(newVal) {};
};
int main ( void )
{
std::list < base<?> > base_collection;
return 0;
}
我希望我当前的项目尽可能灵活和动态,当需要新的派生类时,几乎没有额外的编码,而且我当前的实现使得这样的列表存在很重要。
是否有一种常用,有益和清洁的方法来实现这一目标?
答案 0 :(得分:3)
不完全清楚为什么你需要这样做,或者你打算对列表的元素执行什么操作(顺便说一下,考虑使用std向量)。我建议你创建一个基于非模板化的基类继承自:
struct mainbase {
virtual ~mainbase() = default;
};
template <class T>
class base : public mainbase
{
public:
T val;
base(T newVal): val(newVal) {};
};
class derived : public base<int>
{
public:
derived(int newVal): base(newVal) {};
};
int main ( void )
{
std::list < std::unique_ptr<mainbase>> > base_collection;
return 0;
}
毕竟,如果您要将它们全部放在向量中,您很可能需要一组可以对这些对象执行的通用操作。将它们放在mainbase
。
正如@BenjaminLindley指出的那样,你不能通过值来实现多态性。这就是为什么你要使用指针(such as unique_ptr):std::unique_ptr<mainbase>
。
使用C ++ 17,std::any的提案(正常)可以替代使用,但您仍然需要执行特定的转换才能获得具有正确类型的内容。
答案 1 :(得分:3)
可能的实现是使用双重调度:
#include <iostream>
#include <list>
struct visitor;
struct dispatchable {
virtual void accept(visitor &v) = 0;
};
template <class>
struct base;
struct visitor {
template<typename T>
void visit(base<T> &);
};
template <class T>
struct base: dispatchable {
T val;
base(T newVal): val(newVal) {};
void accept(visitor &v) override { v.visit(*this); }
};
struct derivedInt : base<int> {
derivedInt(int newVal): base(newVal) {};
};
struct derivedDouble : base<double> {
derivedDouble(double newVal): base(newVal) {};
};
template<>
void visitor::visit(base<int> &) {
std::cout << "int" << std::endl;
}
template<>
void visitor::visit(base<double> &) {
std::cout << "double" << std::endl;
}
int main ( void ) {
visitor v{};
std::list <dispatchable*> coll;
coll.push_back(new derivedInt{42});
coll.push_back(new derivedDouble{.42});
for(auto d: coll) d->accept(v);
}
这样,您只需要定义处理要引入的新base<T>
类型的专用函数。
例如,如果要使用base<char>
,则必须定义:
template<>
void visitor::visit(base<char> &) {
std::cout << "char" << std::endl;
}
请注意,我认为您希望以不同的方式处理base<T>
的每个专精。否则,足以定义通用成员函数visitor::visit
并删除特化。
旁注:不要使用裸指针 这是一个例子。在生产代码中,我会使用智能指针。