C++ : Vector of template class

后端 未结 4 1887
灰色年华
灰色年华 2020-12-10 04:39

I have a template class named Cell as follows:-

templateclass Cell
{
    string header, T data;
}

Now I want another class N

相关标签:
4条回答
  • 2020-12-10 05:20

    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.

    0 讨论(0)
  • 2020-12-10 05:21

    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.

    0 讨论(0)
  • 2020-12-10 05:31

    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;
        ...
    }
    
    0 讨论(0)
  • 2020-12-10 05:33

    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).

    0 讨论(0)
提交回复
热议问题