0

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

Community
  • 1
  • 1
  • Why is this question tagged with CUDA? Is this actually GPU code you are writing here? – talonmies May 26 '14 at 06:16
  • "virtual methods not being supported" - wat – M.M May 26 '14 at 06:31
  • @mattmcnabb that would be because this is actually CUDA C not standard C++. CUDA doesn't support virtual functions or inheritance from a base class with virtual functions being passed as arguments to GPU functions – talonmies May 26 '14 at 06:45
  • I think I can answer your previous question now – M.M May 26 '14 at 06:56
  • 1
    Does the `index` need to be a runtime value, or could you make it a template parameter? – Xeo May 26 '14 at 07:09
  • It's GPU code, which is why it was tagged with CUDA, but there's nothing CUDA specific about this. I've removed the tag. The index is a runtime value yes and it is quite crucial that I can enumerate and index into the individual components. – Asger Hoedt Oct 04 '16 at 12:27

1 Answers1

1

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;
}
Nik
  • 1,294
  • 10
  • 16
  • Sorry for the extremely late reply. This seems to solve a different problem, as now the index is gone. It's quite important to me that I can index into my list of components and that the actual type of the i'th component is hidden. – Asger Hoedt Oct 04 '16 at 12:31