简体   繁体   中英

C++ Polymorphism & Variadic Templates

Problem 1: I have the following code:

template<typename T, typename S>
class Base {
    virtual void fun(const T& arg1, const S& arg2) = 0;
private:
    T v1;
    S v2;
};

class Derived1 : public Base<int, double> {
public:   
   virtual void fun(int &arg1, double &arg2) override {
       // do some special stuff
   }
};

class Derived2 : public Base<float, int> {
public:   
   virtual void fun(float &arg1, int &arg2) override {
       // do some special stuff
   }
};

I need to collect all references to these objects (Derived1 & Derived2) in a single vector to loop over them and invoke fun on each object.

Problem 2: Same problem, but base has variadic template parameters now

template<typename T, typename ... S>
class Base {
    virtual void fun(const T& arg1) = 0;
private:
    T v1;
    std::tuple<std::vector<S>...> v2;
};

class Derived1 : public Base<int, double, int, int> {
public:   
   virtual void fun(int &arg1) override {
       // do some special stuff
   }
};

class Derived2 : public Base<float, int, double, double> {
public:   
   virtual void fun(float &arg1) override {
       // do some special stuff
   }
};

Is there a convenient way to collect all references to the Derived1 and Derived2 objects in a single vector?

So you've got a fundemental misunderstanding of what a template is. Variadic has nothing to do with your problem.

Take the following template:

template <typename T>
class Foo
{
T member_;
public:
   Foo(){}
   T& member() {return member_;}
   virtual bar() {printf("bar");}
};

int main(int argc,char* argv)
{
   Foo<int> a;
   Foo<string> b;
}

What is the relationship between the types of a and b ? The answer is there is none. Sure, they pull from the same code base, but they are completey different types, with different sizes, interfaces, ect. And with template specializations, you can't make ANY guarentee with how similar they are.

What you are trying to do is template a derivation of a polymorphic class. So do just that, ie:

class Bar
{
public:
  virtual bar() = 0;
};
template <typename T>
class Foo : public Bar
{
T member_;
public:
   Foo(){}
   T& member() {return member_;}
   virtual bar() {printf("bar");}
};

Then everything can be collected and access the interface of Bar.

Just like all inheritance, you can continue to provide child classes:

 class Derived1 : public Foo<int> { virtual bar() {printf("derived1");}};
 class Derived2 : public Foo<string> { virtual bar() {printf("derived2");}};

Derived1 is a Foo<int> is a Bar , Derived1 is a Foo<string> is a Bar .

Add another non-templated base class:

class Intf {
 public:
  virtual void fun() = 0;
};

template<typename T, typename ... S>
class Base : public Intf {
 protected:
  T v1;
  std::tuple<S...> v2;
};

class Derived1 : public Base<int, double, int, int> {
public:   
 virtual void fun() override {
   // do some special stuff
   std::get<0>(v2) = 10;
   std::get<1>(v2) = 2.5; 
   // ...
 }
};

class Derived2 : public Base<float, int, double, double> {
 public:   
  virtual void fun() override {
     // do some special stuff
     float first_elem = std::get<0>(v2);
     int some_int = std::get<1>(v2);
     // ...
  }
};

std::vector<std::shared_ptr<Intf>> vec;
vec.push_back(std::make_shared<Derived1>());
vec.push_back(std::make_shared<Derived2>());

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM