c++templatesc++17rttistatic-polymorphism

static polymorphism and template Containers


I'm trying to use the static polymorphism and template to create a container that can hold more the one type, from what I know about template it can't be done, but I'm hoping that I'm wrong and there is a way. I have the following classes:

template<class Derived>
class base
{
public:
    base(string);
    void clean()
    {
        cout << "I'm cleannig \n";
    }
    void process()
    {
        static_cast<Derived*>(this)->setup();
        static_cast<Derived*>(this)->run();
        static_cast<Derived*>(this)->cleanup();
    }
    string name;
};

template<class Derived>
base<Derived>::base(string y):name(y)
{
}


class derived : public  base<derived> 
{
    friend class base<derived>;
    void setup() {cout << "derived setup \n"; }
    void run() { cout << "derived run \n"; }
    void cleanup() { cout << "derived cleanup \n"; }

};


class derived1 : public base<derived1> 
{
    friend class base<derived1>;
    void setup() {cout << "derived1 setup \n"; }
    void run() { cout << "derived1 run \n"; }
    void cleanup() { cout << "derived1 cleanup \n"; }
};

and I wont to create a container that can hold them, I tried this code -

template <class T>
class Y{
 public:
 std::vector<base<T>> m_vec;   

};


template <typename T>
class D:public Y<T>
{
    public:
    friend class Y<T>;
    void print()
    {
        for(auto& e: Y<T>::m_vec)
        {
            e.process();
        }
    } 
};


int main()
{ 
    base<derived>* b =  new base<derived>;
    base<derived1>* c =  new base<derived1>;

    D<derived> y;
    y.m_vec.push_back(b);
    y.m_vec.push_back(c);
    y.print();
}

but its not working i tryed to do this:

 y.m_vec.push_back(static_cast<base<derived>>(c));

and I'm getting this error:

error: no matching function for call to ‘std::vector, std::allocator > >::push_back(base*&)’ y.m_vec.push_back(b);


Solution

  • after some testing and digging the answer is that there isn't a way to do it. but you can use std::any like @formerlyknownas_463035818 suggested declare the std::vector as :

    std::vector<std::any> m_vec;
    

    Instead of

    std::vector<base<T>> m_vec;
    

    and use the boost demangle function to get the type -

    std::string name(boost::core::demangle(e.type().name()));
    

    and then use some kind of factory functio to any_cast to the type you need

     if(!name.compare("base<derived1>*") )
     {
         try {
                 auto* r = any_cast<base<derived1>*>(e);
                 r->process();
             }
             catch(const std::bad_any_cast& e) {
                 std::cout << e.what() << '\n';
             }
      }
      else
      {
         try {
             auto *r = any_cast<base<derived> *>(e);
             r->process();
         }
         catch(const std::bad_any_cast& e) {
             std::cout << e.what() << '\n';
         }
       }
    

    or instead of using the demangle name and use string compare you can use the type() function of the class any and compare is to the typeid like this:

        if(e.type()==typeid(base<derived1>*))