How to create an array of templated class objects?
As has been said before, C++ templates don't work like that.
At the same, using inheritance and vectors of pointers is not suitable for implementations of DB records because of performance limitations.
Take a step back and look at the problem in a more abstract way. As I understand from your code, the intent is to package an arbitrary number of fields of different types into a continuous memory block. Schematically:
struct DBRecord {
Type1 f1;
Type2 f2;
Type3 f3;
Type4 f4;
// etc...
}
You can achieve this by a bit ugly but practical construct consisting of an abstract template declaration and several specializations.
The declaration would look like this:
template <
typename T1,
typename T2 = void,
typename T3 = void,
typename T4 = void,
typename T5 = void,
typename T6 = void,
typename T7 = void,
typename T8 = void,
typename T9 = void,
typename T10 = void
> struct DBRecord;
It limits a max number of fields to some specific number obviously. If you need a truly arbitrary number of fields you need to switch to column-oriented paradigm.
Then, partial specializations should declare anatomy of structures for each number of arguments from 1 to 10:
template <
typename T1
> struct DBRecord <T1, void, void, void, void, void, void, void, void, void>
{
int id;
T1 f1;
DBRecord(int ID, T1 F1) {/*...*/};
};
template <
typename T1,
typename T2
> struct DBRecord <T1, T2, void, void, void, void, void, void, void, void>
{
int id;
T1 f1;
T2 f2;
DBRecord(int ID, T1 F1, T2 F2) {/*...*/};
};
// etc...
Now, you can allocate tables as arrays of records of certain types in one new[]
call if you want.
And, you don't normally care about destruction of each field, since you free memory of the whole structure.
Macros can help to make declaration of such specializations somewhat more compact.
Field<T1>
and Field<T2>
are two completely different types. To treat them in a vector you need to generialize then somewhere. You may write AbstractField
and
struct AbstractField{
virtual ~AbstractField() = 0;
};
template<class T,int fieldTypeId>
class Field: public AbstractField{
private:
T field;
public:
const static int field_type;
public:
virtual ~Field(){}
};
class Database_Record{
std::vector<AbstractField*> record;
public:
~Database_Record(){
//delete all AbstractFields in vector
}
};
and then keep a vector
of AbstractField
. also use vector
instead of []
. Use AbstractField*
instead of AbstractField
and write at least one pure virtual in AbstractField
.
you may make the destructor of AbstractField
pure virtual. and don't forget to delete all AbstractField
s. in ~Database_Record()
You are going the wrong way.
Templates are used to create distinct types: std::vector<int>
and std::vector<float>
are distinct in much the same way (and as much) as int
and float
are.
Your syntax is also wrong; to create a dynamic array you'd put the following member in your Database_Record
:
std::vector<Field> record; // if this was possible; however, it's not
To put several objects of distinct type into a single array, they ought to have a common base class.
In order to create an array of different types you need a base class for the objects and the array will be an array of pointers to that base class. So, for example,
class Field
{
public:
virtual ~Field() {}
virtual std::string toString() const = 0;
// and possibly other interface functions...
};
template <class T> FieldImpl : public Field
{
public:
virtual std::string toString() const
{
std::stringstream ss;
ss << val;
return ss.str();
}
// implementation of possibly other interface functions
private:
T val;
}
will be the types you need. The array will then be something like
std::vector<std::unique_ptr<Field>> my_array;
You can then do stuff with your array using the interface functions, e. g.
my_array[i]->toString();