Reputation: 61
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
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;
}
Note that
v_t
is the type of the variantv_t
can have more types among which you can choose to populate the arrayboost::visitor
Upvotes: 1
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):
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.
Use a boost::variant
, if you are new to C++ then I don't recommend tackling this sort of thing right away.
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
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
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