C++ virtual template function best workaround

140 Views Asked by At

I have a class ComInterface which has a overloaded function send. This function is overloaded for many different enum class types.

class ComInterface{
public:
    virtual void send(MotorCommand cmd);
    virtual void send(ValveCommand cmd);
    virtual void send(ThrottleCommand cmd);
};

Then I have a derrived class CanCom

class CanCom: public ComInterface{
public:
    void send(uint32_t CanID, uint8_t cmd);
    virtual void send(MotorCommand cmd){
        send(1, (uint8_t) cmd); //1 is the Motor specific address
    }
    virtual void send(ValveCommand cmd){
        send(2, (uint8_t) cmd); //2 is the Valve specific address
    }
    virtual void send(ThrottleCommand cmd){
        send(3, (uint8_t) cmd); 
    }
};

This is the code so far. Since I have many of these enum classes (like MotorCommand), I would prefer to use a template. Something like:

class ComInterface{
public:
    template <typename T>
    virtual void send(T cmd);
};

The specific address would be then inserted with a template variable, as proposed here C++ template function associate parameter type with integer So something like [as proposed from Jarod42 in the linked question]

template <typename T>
constexpr uint32_t can_address = [](){ throw "Should be specialized"; }();
template <> constexpr uint32_t can_address<MotorCommand> = 1;
template <> constexpr uint32_t can_address<ValveCommand> = 2;
template <> constexpr uint32_t can_address<ThrottleCommand> = 3;


template <typename T> send(T cmd){
    send(can_address<T>, (uint8_t) msg);
}

But now I have the problem that I can't use templates AND virtual functions. After some research, I think the best way to resolve that is by using policy based design. So ComInterface is a template class and there is something like a CanImplementation class that is passed as a template parameter. Unfortunatley, this would mean that the type of ComInterface would have to be adaptet at every place it is used, which is not possible in my case.

My next idea was to have a new class "TypeToIDConverter", which converts the type to a ID. But then this class would have to be derived again to "TypeToCanIDConverter", and again, since it would have to be virtual, no templates could be used. I thought about using a normal override, and then convert the base type converter which would be stored in ComInterface to the derived class with a static_cast. However, Im not sure this will work, and it would be a ugly solution for sure!

Other ideas I found is type errasure and the visitor principle. However, Im not sure how I would use them here.

Is there a elegant solution for this? Something that I don't have to write a send function for every enum class type, but also keeps the Interface general and leaves room for new implementations for other protocols (like a LinCom or a I2CCom)?

Thank you a lot in advance! This problem bricks my head for days already...

0

There are 0 best solutions below