0

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?

Krizz
  • 11,362
  • 1
  • 30
  • 43
moo
  • 486
  • 8
  • 22
  • A `std::vector` can hold only elements of the same type. Consequently, a `std::vector` would be inappropriate in you case. – 101010 Oct 14 '14 at 19:29
  • 4
    "I need to collect" -- no, you don't need that. You may *think* that you need that, but your actual problem, which you didn't tell us, most likely has a completely different and much better solution. – Kerrek SB Oct 14 '14 at 19:33
  • `abstract` is not a keyword in C++. What language are you writing in? Second, problem 1 and problem 2 nearly unrelated, and you should ask 1 question at a time. This isn't the "ask QUESTIONS" interface. And `std::tuple>` is also not valid C++, `...` cannot be used there. "those objects" is also unclear, I have no idea what "those" refers to. – Yakk - Adam Nevraumont Oct 14 '14 at 19:44
  • I don't think that they are unrelated. And I am very sorry that english is not my native language. – moo Oct 14 '14 at 19:47
  • 2
    @KerrekSB His comments on my answer support your statement. – IdeaHat Oct 14 '14 at 20:27
  • 1
    @MadScienceDreams I concur, and knowing we have a model in-code that clearly isn't going to acquire altitude, it would be interesting to see what is the core, *real*, problem being tackled. The aroma of an [XY problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) is fairly pungent at this point. – WhozCraig Oct 14 '14 at 20:36
  • The real problem is this EntityClass http://pastebin.com/DYFxZgNW. A concrete entitity (think of relations in relational databases) is dervied from it and implements the select function. The problem is now, that this is part of a database systems and I need to reference the different entities somehow to answer queries. The set of entities is also dynamic and depends on a given database schema-description file. Basically, I am implementing an ER database prototype in main memory. – moo Oct 14 '14 at 20:52

2 Answers2

3

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.

IdeaHat
  • 7,641
  • 1
  • 22
  • 53
  • Yeah, I understand that, but in my case, the Base class implements some common functionality for all subclasses: http://pastebin.com/192Xaef0 All subclasses now instantiate a certain EntitySet with a specific tuple and key. EDIT: I forgot to post the virtual part in EntitySet: virtual Tuple select() = 0; – moo Oct 14 '14 at 19:35
  • @moo right. In your case, you'd want to provide a `Base` *interface* with just the fun() class. Then, you can have an *abstract class* templated `BaseHelper` class that inherits from the `Base` with your funky template stuff. Then you can have an concrete `Derived1`. I'll update my question to reflect that. – IdeaHat Oct 14 '14 at 20:08
  • Okay, that is a solution that doesn't work for me. The reason for this is, that my virtual functions have arguments and return values that depend on the parameters. (see e.g. deleteTuple). – moo Oct 14 '14 at 20:16
  • @moo then why on earth do you want to collect them? If Derived1 and Derived2 have incompatible interfaces, then you cound just use a `std::tuple` or a struct of instances and be done with it. But this design has a peculiar odor. – IdeaHat Oct 14 '14 at 20:26
  • I need a dictionary of all existing entity sets. – moo Oct 14 '14 at 20:30
  • 2
    @moo then you're attempting to collect utterly unrelated types. You said "...the Base class implements some common functionality..." That right there is the fundamental issue you seem have a hard time realizing: **There is no "the Base class".**. Base is a template, and its variant expansions form base *classes*, not "the" base class. This *might* be possible by employing [*type erasure*](http://stackoverflow.com/questions/5450159/type-erasure-techniques) techniques. (My head is too loaded with work to give it much thought right now), but just as it sits, what you want is simply not feasible. – WhozCraig Oct 14 '14 at 20:30
  • 1
    @WhozCraig and most likely, a smelly solution to a otherwise solvable problem. – IdeaHat Oct 14 '14 at 20:35
  • @MadScienceDreams what would be a possible other solution? I thought about making the Parameters Pointers and let the parameter be derived from a common base class. But this has other drawbacks. – moo Oct 14 '14 at 20:38
1

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>());
Krizz
  • 11,362
  • 1
  • 30
  • 43
  • I need a vector because there can be multiple instances values for a specific type and I need to store them all. – moo Oct 14 '14 at 19:42
  • @moo: so in Derived 2, you need a vector of floats, vector of ints and 2 vectors of doubles? – Krizz Oct 14 '14 at 19:42
  • exactly. But that was not my questions. I asked how I can collect a bunch of Derived1 and Derived2 objects in a single vector (outside of those classes in the program itself). – moo Oct 14 '14 at 19:45
  • That does not work, as they have different parameters. – moo Oct 14 '14 at 20:02
  • @moo, Ah right, too tired today. Updated the answer. – Krizz Oct 14 '14 at 20:36
  • see my updated question, fun now depends on the parameter types. – moo Oct 14 '14 at 20:44
  • @moo: then, you have to move your virtual function back to `Base` class and then cast every access to "Derived". – Krizz Oct 15 '14 at 08:04