Home > Back-end >  vector of a template class with unknown parameters
vector of a template class with unknown parameters

Time:10-03

I am working on a program that has to use std::vector, while the types of elements are unknown. The std::vector can hold different types of elements. Specifically, these types are enumerated from a template class. What I want to do is something like below,

#include <vector>

template <size_t N>
class Element{
  int array[N];
};

int main(){
  std::vector<Element> vec;
  // do something
}

where, class Element is the types of objects to be stored in the vector. It holds an array of an arbitrary size. The vector stores some Elements objects with unknown paremter N.

One solution I found is something like below, since the values of N are known at compilation time.

std::vector<std::variant<Element<1>, Element<2>, Element<3> > vec;

But it would be tricky as I have to enumerate all of them, and the application changes a lot.

I know this simple example can be resolved through dynamic memory allocation, but this is just an example, the program is much more complex.

Is there a better solution for this?

CodePudding user response:

I could suggest two approaches for this.

Ditching Templates

You could ditch the template parameter in your Element class and have it contain a std::vector whose size is set upon construction and never changed. Something like this:

class Element {
public:
    Element(std::size_t size) : m_vector(size) {};

private:
    std::vector<int> m_vector;
};

And then you use the m_vector just as if it was an array. No problems in your main() here.

Using Inheritance and Polymorphism

I think you refer to this when you talk about dynamic allocation, but I'll include it anyways. If you want to use templates, you can have your class Element inherit from a non-templated abstract class to have an interface of all the methods. For example:

class ElementBase {
public:
    ElementBase() = default;
    virtual ~ElementBase() = default;
    
    virtual std::size_t arraySize() const = 0;
    virtual const int *array() const = 0;
};


template<std::size_t N>
class Element : public ElementBase {
public:
    Element() = default;
    ~Element() override = default;
    
    std::size_t arraySize() const override {
        return N;
    }
    
    const int *array() const override {
        return m_array;
    } 

private:
    int m_array[N];
};

With this approach you cannot have a std::vector<ElementBase> in your main() because the class is abstract, but you can have a std::vector<ElementBase*> or something like std::vector<std::unique_ptr<ElementBase>> if you are going to need dynamic allocation.

  • Related