У меня есть два класса, которые я использую для представления некоторого оборудования: класс Button и класс InputPin, которые представляют собой кнопку, которая будет изменять значение входного вывода микросхемы при его нажатии.Простой пример из них:
template <int pinNumber> class InputPin
{
static bool IsHigh()
{
return ( (*portAddress) & (1<<pinNumber) );
}
};
template <typename InputPin> class Button
{
static bool IsPressed()
{
return !InputPin::IsHigh();
}
};
Это прекрасно работает, и при использовании шаблонов классов приведенное ниже условие будет скомпилировано так же плотно, как если бы я писал его вручную при сборке (одна инструкция).
Button < InputPin<1> > powerButton;
if (powerButton.IsPressed())
........;
Однако я расширяю его для обработки прерываний, и у меня возникла проблема с циклическими ссылками.
По сравнению с исходным InputPin, новый класс InputPinIRQ имеет дополнительную статическую функцию-член, которая будет автоматически вызываться аппаратным обеспечением при изменении значения контакта.Я хотел бы, чтобы он мог уведомить класс Button об этом, чтобы класс Button мог затем уведомить основное приложение о том, что оно было нажато / отпущено.В настоящее время я делаю это, передавая указатели на функции обратного вызова.Чтобы код обратного вызова был встроен компилятором, я считаю, что необходимо передать эти указатели функций в качестве параметров шаблона.Итак, теперь у обоих новых классов есть дополнительный параметр шаблона, который является указателем на функцию обратного вызова.К сожалению, это дает мне циклическую ссылку, потому что для создания экземпляра класса ButtonIRQ мне теперь нужно сделать что-то вроде этого:
ButtonIRQ<InputPinIRQ<1, ButtonIRQ< Inp.... >::OnPinChange>, OnButtonChange> pB;
, где ...... представляет циклическую ссылку.
Кто-нибудь знает, как мне избежать этой циркулярной ссылки?Я новичок в шаблонах, поэтому, возможно, мне не хватает чего-то очень простого.
пс.важно, чтобы компилятор точно знал, какой код будет запущен при возникновении прерывания, поскольку он затем выполняет очень полезную оптимизацию - он может встроить функцию обратного вызова и буквально вставить код функции обратного вызова по точному адресу, который вызывается через ah /ш прерывание.