The most straightforward variant is to simply not use templates but to overload the addElement()
function:
void addElement(Component1 element)
{
this->element1List.push_back(element);
}
void addElement(Component2 element)
{
this->element2List.push_back(element);
}
// ... etc
However, this might get tedious if you have many of these (and you don't just have addElement()
, I guess). Using a macro to generate the code for each type could still do the job with reasonable effort.
If you really want to use templates, you could use a template function and specialize the template function for each type. Still, this doesn't reduce the amount of code repetition when compared with the above approach. Also, you could still reduce it using macros to generate the code.
However, there's hope for doing this in a generic way. Firstly, let's create a type that holds the list:
template<typename T>
struct ComponentContainer
{
list<T> componentList;
};
Now, the derived class just inherits from this class and uses C++ type system to locate the correct container baseclass:
class MyClass:
ComponentContainer<Component1>,
ComponentContainer<Component2>,
ComponentContainer<Component3>
{
public:
template<typename T>
void addElement(T value)
{
ComponentContainer<T>& container = *this;
container.componentList.push_back(value);
}
}
Notes here:
- This uses private inheritance, which is very similar to the containment you originally used.
- Even though
ComponentContainer
is a baseclass, it doesn't have any virtual functions and not even a virtual destructor. Yes, this is dangerous and should be documented clearly. I wouldn't add a virtual destructor though, because of the overhead it has and because it shouldn't be needed.
- You could drop the intermediate container altogether and derive from
list<T>
, too. I didn't because it will make all of list
's memberfunctions available in class MyClass
(even if not publicly), which might be confusing.
- You can't put the
addElement()
function into the base class template to avoid the template in the derived class. The simple reason is that the different baseclasses are scanned in order for a addElement()
function and only then overload resolution is performed. The compiler will only find the addElement()
in the first baseclass therefore.
- This is a plain C++98 solution, for C++11 I'd look at the type-based tuple lookup solutions suggested by Jens and Richard.