Reputation: 75
I'm refactoring some code currently and I was hoping SO could help me figure out a clever way of reducing a lot of boilerplate into a few simple methods. My problem is similar to C++ function dispatch with template parameters.
Basically I have a couple of classes (7 so far) that all conform to the same templated interface, but do not inherit from any common superclass, due to virtual methods not being supported.
Lets say the interface is
template<typename T> class IComponent : public T {
int Food() { return T::Food(); }
bool FooBarred() { return T::FooBarred(); }
};
and then I have two classes conforming to that interface
class ComponentA {
int Food() { return 42; }
bool FooBarred() { return false; }
};
class ComponentB {
int Food() { return 5; }
bool FooBarred() { return true; }
};
I then combine these Components in arbitrary ways in a number of compositing classes (currently I have 12 of these), which can look like this.
class MultiComponent {
ComponentA cA;
ComponentB cB;
ComponentC cC;
int NumComponents() { return 2; }
int Food(index i) {
if (i == 0)
return cA.Food();
else if (i == 1)
return cB.Food();
else // if (i == 2)
return cC.Food();
}
bool FooBarred(index i) {
if (i == 0)
return cA.FooBarred();
else if (i == 1)
return cB.FooBarred();
else // if (i == 2)
return cC.FooBarred();
}
};
With 7 component classes implementing 9 methods from the interface and being combined by 12 different wrappers (so far) this codebase is going to explode into almost nothing but dynamic dispatching using a bunch of if's.
What I would like to reduce this to is some kind of clever dispatcher a la
template <typename RetVal, typename C>
RetVal ApplyTo(int index, RetVal(*fn)(const C* component)) {
if (index == 0)
return fn(cA);
else if (index == 1)
return fn(cB);
else
return fn(cC);
}
that I can use to apply an operator to the i'th component and that way I'd only have to implement this ApplyTo once for every composite class and I would be able to access my components and all their methods and properties via this single method.
Is it in any way possible to do something like this? Or does SO have another idea as to how I can structure this in a nicer way either with templates or possibly macroes. (As I'm afraid the typesystem is going to get in the way of any templated solution.)
Cheers asger
Upvotes: 0
Views: 826
Reputation: 1334
I have tried something, have a look if this how you want to generalize the code:
#include <iostream>
template<typename T>
class IComponent : public T {
public:
int Food() { return T::Food(); }
bool FooBarred() { return T::FooBarred(); }
};
class ComponentA{
public:
int Food() { return 42; }
bool FooBarred() { return false; }
};
class ComponentB{
public:
int Food() { return 5; }
bool FooBarred() { return true; }
};
class ComponentC{
public:
int Food() { return 6; }
bool FooBarred() { return true; }
};
//An example WRAPPER class
class MultiComponent {
public:
int NumComponents() { return 2; }
template<typename T>
bool foo(IComponent<T>* object)
{
object->Food();
return object->FooBarred();
}
};
//Routes calls to specific instance of components via wrapper object
template <typename RetVal, typename C, typename Wrapper, typename Func>
RetVal ApplyTo(Func func, Wrapper& wrapper )
{
IComponent<C> obj;
return (wrapper.*func)(&obj);
}
//wrapper call backs
typedef bool (MultiComponent::*CallBackC)(IComponent<ComponentC>*);
typedef bool (MultiComponent::*CallBackA)(IComponent<ComponentA>*);
typedef bool (MultiComponent::*CallBackB)(IComponent<ComponentB>*);
int main()
{
MultiComponent wrapper;
//call Component C
CallBackC callback;
callback = &MultiComponent::foo<ComponentC> ;
bool result = ApplyTo<bool, ComponentC, MultiComponent, CallBackC>(callback, wrapper);
std::cout<<"Result of C "<<result<<std::endl;
//call Component A
CallBackA callbackA;
callbackA = &MultiComponent::foo<ComponentA> ;
result = ApplyTo<bool, ComponentA, MultiComponent, CallBackA>(callbackA, wrapper);
std::cout<<"Result of A "<<result<<std::endl;
return 0;
}
Upvotes: 1