I have a template class named Cell as follows:-
template<class T>class Cell
{
string header, T data;
}
Now I want another class Named Row. Row will have a vector named Cells such that I can add both Cell and Cell type elements to that vector. Is it possible?
If so, how can I do that?
Thanks in advance.
With the extra detail you've provided, the first two answers won't work. What you require is a type known as a variant for the cell and then you can have a vector of those. For example:-
enum CellType
{
Int,
Float,
// etc
};
class Cell
{
CellType type;
union
{
int i;
float f;
// etc
};
};
class Vector
{
vector <Cell> cells;
};
This, however, is a pain to add new types to as it requires a lot of code to maintain. An alternative could use the cell template with a common base class:-
class ICell
{
// list of cell methods
};
template <class T>
class Cell : public ICell
{
T data;
// implementation of cell methods
};
class Vector
{
vector <ICell *> cells;
};
This might work better as you have less code initially to update to add a new cell type but you have to use a pointer type in the cells vector. If you stored the cell by value, vector <ICell>
, then you will lose data due to object slicing.
The reason why this is NOT possible in C++, but possible in Java/Python is because: in a C++ vector, the STL container's storage (returned by vector::data()) contains all the object instantiations sequencially packed. In which each element must have the same size. This makes addressing fast and convenient. Therefore, suppose you define a template class A,
template <class T>
class A{
int id;
T obj;
};
Its size will depend on the template variable "T obj". Pushing the same class A of different template type T will make each element in the vector having different sizes, thus, this is impossible. The only way is to use vector of shared_ptr or unique_ptr of a base class. Both shared_ptr and unique_ptr are supported by C++11 and Boost. Each derived-class element can have different template types. In this way, when the base class pointer's destructor is called, the derived class's destructor will be invoked. For example,
#include <memory>
#include <vector>
#include <iostream>
#include <string>
using namespace std;
class A{};
template <class T>
class AImpl : public A{
public:
T obj;
AImpl(T _obj):obj(_obj){}
~AImpl(){
cout << "Deleting " << obj << endl;
}
};
int main(int argc, char** argv)
{
AImpl <string>* a1 = new AImpl <string> ("string1234");
AImpl <int>* a2 = new AImpl <int> (1234);
AImpl <double>* a3 = new AImpl <double> (1.234);
vector <shared_ptr<A>> As;
As.push_back(shared_ptr<A>(a1));
As.push_back(shared_ptr<A>(a2));
As.push_back(shared_ptr<A>(a3));
}
Remember to compile with -std=c++11 to enable C++11.
Output:
Deleting string1234
Deleting 1234
Deleting 1.234
And you get what you want! :)
In Java/Python, every class-object variable is actually a pointer, thus, a Java Array of A or a Python list of A is equivalent to a C++ array of pointers of A. Thus, you get essentially the same functionality without explicit creating shared_ptrs.
The other answer is good, but you probably wanted:
template<class T>
class Row
{
private:
class Cell {
string header;
T data;
}
std::vector<Cell> cells;
...
}
Something like this?
template<class T>
class Row
{
private:
std::vector<Cell<T> > cells;
};
Okay, this answer is incorrect.
So, if you want to store in one vector
different cells - you should use some dynamic type identification (you can use one base-class and store pointer to it in vector, that use only virtual functions, that are overrided in all derived classes, you can store something like boost::any
and save some type-identification
for each inserted element, for cast them into real type and work with it).