没有模板参数

时间:2016-07-05 22:07:36

标签: c++ class c++11 polymorphism containers

我想知道你是否可以拥有一个包含不同模板参数的对象的容器。

我试图达到这样的目标:

#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;
}

我希望我当前的项目尽可能灵活和动态,当需要新的派生类时,几乎没有额外的编码,而且我当前的实现使得这样的列表存在很重要。

是否有一种常用,有益和清洁的方法来实现这一目标?

2 个答案:

答案 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并删除特化。

旁注:不要使用裸指针 这是一个例子。在生产代码中,我会使用智能指针。