I have two classes that I'm using to represent some hardware: A Button and an InputPin class which represent a button that will change the value of an IC's input pin when it's pressed down. A simple example of them is:
template <int pinNumber> class InputPin
{
static bool IsHigh()
{
return ( (*portAddress) & (1<<pinNumber) );
}
};
template <typename InputPin> class Button
{
static bool IsPressed()
{
return !InputPin::IsHigh();
}
};
This works beautifully and by using class templates, the condition below will compile as tightly as if I'd handwritten it in assembly (a single instruction).
Button < InputPin<1> > powerButton;
if (powerButton.IsPressed())
........;
However, I am extending it to deal with interrupts and have got a problem with circular references.
Compared to the original InputPin, a new InputPinIRQ class has an extra static member function that will be called automatically by the hardware when the pin value changes. I'd like it to be able to notify the Button class of this, so that the Button class can then notify the main application that it has been pressed/released. I am currently doing this with function pointers to callbacks. In order for the callback code to be inlined by the compiler, I need to pass the function pointers as template parameters. So now, both of the new classes have an extra template parameter that is a pointer to a callback function. Unfortunately this gives me a circular reference because to instantiate a ButtonIRQ class I now have to do something like this:
ButtonIRQ< InputPinIRQ< A1, ButtonIRQ<....>::OnPinChange, OnButtonChange > pB;
where the <...... represents the circular reference.
Does anyone know how I can avoid this circular reference? I am new to templates, so might be missing something really simple.
It's important that the compiler knows exactly what code will be run when the interrupt occurs as it then does some very useful optimisation - it is able to inline the callback function and literally inserts the callback function's code at the exact address that is called on a h/w interrupt.