jesta
jesta

Reputation: 61

Holding Template Class Objects in Array

I have to hold different type of datas in one array for my project. I've created a template class for generating objects.

template<class Queue>
class Template  {

public:
    Queue value;
    Template(Queue input) {
        value = input;
    }

};

But I can't hold them in one array without using abstract class. I've created a void pointer array for this. And I used it liked that;

void *array[21];
array[index] = new Template<int>(number);
array[index] = new Template<string>(text);

Is there any possible solution without abstract classes? I mean, can i hold this template objects in template class' array?

Upvotes: 0

Views: 2194

Answers (3)

Lorah Attkins
Lorah Attkins

Reputation: 5856

I'd do it using variant types. You can roll out your own but prefer using boost::variant :

#include <boost/variant.hpp>
#include <iostream>
#include <string>

using namespace std;

template<class Queue>
class Template  
{
public:
    Queue value;
    Template() = default; 
    Template(Queue input) {
        value = input;
    }
};

template<typename T>
std::ostream& operator<<(std::ostream& os, Template<T> const& t)
{
    os << t.value; 
    return os; 
}

int main ()
{
    using v_t = boost::variant<Template<int>, Template<string>>; 

    v_t ar[2]; 

    ar[0] = Template<int>(1); 
    ar[1] = Template<string>("lmfao"); 

    for (auto&& elem : ar) cout << elem << endl;
}

Demo

Note that

  • v_t is the type of the variant
  • v_t can have more types among which you can choose to populate the array
  • the output operator was only overloaded for demonstration
  • you get extra functionality by boost::visitor

Upvotes: 1

SirGuy
SirGuy

Reputation: 10760

This is usually a sign that you should rethink your code structure at a higher level so that you don't need this at all.

Otherwise you have four choices that I see (five if you count the "don't do this" above):

  1. Use a uniform type that can hold all your types of data (for example a std::string and parse the numeric information out when needed). This functionality could be wrapped in a class that provides member functions to make this easier.

  2. Use a boost::variant, if you are new to C++ then I don't recommend tackling this sort of thing right away.

  3. Use a base class as explained by 101010. I would add that you may want an enum in the base class that tells you what type of data is stored

  4. Use a boost::any, this is even more difficult to use than a variant, even though it's easier to understand.

Without more information on what it is you are trying to achieve, we can't really provide any better guidance on how to proceed.

Upvotes: 2

Dimitrios Bouzas
Dimitrios Bouzas

Reputation: 42889

Create a hierarchy and take advantage of dynamic binding:

class Base  {
public:
  virtual ~Base() {};
  // ...
};

template<class Queue>
class Template : public Base {
    Queue value;
public:
    Template(Queue const &input) :value(input) {}
    // ...
};

And use it as:

Base *array[21];
array[index] = new Template<int>(number);
array[index + 1] = new Template<string>(text);

Furthermore, instead of using raw array and raw pointers use STL facilities like std::array smart pointers (e.g., std::shared_ptr<Base> or std::unique_ptr<Base>):

std::array<std::unique_ptr<Base>, 21> arr;
arr[index].reset(new Template<int>(number));
arr[index + 1].reset(new Template<string>(text));

Also prefer to initialize member variables to the constructor's initializer list than to its body.

Upvotes: 5

Related Questions