Инстанцирование Шаблона класса: какой-либо окольный путь эта циклическая ссылка?

У меня есть два класса, которые я использую для представления некоторых аппаратных средств: Кнопка и класс InputPin, которые представляют кнопку, которая изменит значение входного контакта IC, когда это будет придавлено. Простой пример их:

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 имеет дополнительную статическую функцию членства, которую назовут автоматически аппаратные средства, когда значение контакта изменится. Я хотел бы, чтобы это смогло уведомить класс Кнопки относительно этого, так, чтобы класс Кнопки мог затем уведомить главное приложение, что это было нажато/выпущено. Я в настоящее время делаю это передающими указателями на функции обратного вызова. Для кода обратного вызова, который будет встроен компилятором, я полагаю, что это должно передать эти указатели функции как шаблонные параметры. Таким образом, теперь оба из новых классов имеют дополнительный шаблонный параметр, который является указателем на функцию обратного вызова. К сожалению, это дает мне циклическую ссылку, потому что для инстанцирования класса ButtonIRQ я теперь должен сделать что-то вроде этого:

ButtonIRQ<InputPinIRQ<1, ButtonIRQ< Inp.... >::OnPinChange>, OnButtonChange> pB;

где...... представляет циклическую ссылку.

Кто-либо знает, как я могу избежать этой циклической ссылки? Я плохо знаком с шаблонами, так вероятно, пропускаю что-то действительно простое.

PS важно, чтобы компилятор знал точно, какой код будет выполнен, когда прерывание произойдет как он затем, делает некоторую очень полезную оптимизацию - это может встроить функцию обратного вызова и буквально вводит код функции обратного вызова в точном адресе, который называют на прерывании h/w.

1
задан TimYorke34 15 June 2010 в 19:03
поделиться

4 ответа

Я бы изменил дизайн так, чтобы кнопка была связана с входным контактом:

class Button
{
  boost::smart_ptr<InputPin> p_input_pin;
}

Или изменил класс контактов, чтобы у него был список подписчиков . Это может быть лучший дизайн, поскольку он позволяет многим подписчикам получать уведомления об изменении значения пина. Вы также можете добавить метод (установщик), который устанавливает значение пина.

Вариант использования 1: Нажатие кнопки.
Нажатие кнопки изменяет состояние входного вывода.
Входной контакт уведомляет подписчиков о событии.

Вариант использования 2: прерывание.
Прерывание {объект} изменяет состояние входного вывода.
Входной контакт уведомляет подписчиков о событии.

Шаблон проектирования «Подписчик / Издатель» хорошо подходит для этих случаев использования.

1
ответ дан 2 September 2019 в 23:45
поделиться

В случае, если это поможет кому-то еще, я нашел способ обойти это:

typedef Button< Pin<B7>,  &OnButtonChange > TestButton;

PinIRQ< B7, &TestButton::InputChangedISR > irqPin; 
TestButton testButton;

Объекту Button на самом деле не нужно ничего знать о Прерывание PinIRQ, поэтому я могу просто объявить его, используя исходный (без прерывания) класс Pin, которому не требуется ничего, связанного с передачей Button в качестве параметра шаблона. Я могу создать экземпляр полного класса PinIRQ с помощью этого объявления Button, и все работает отлично.

Я получаю PinIRQ из объекта Pin, чтобы позволить мне «перегрузить» шаблон класса, чтобы получить Pin и PinIRQ

Это не самый приятный фрагмент кода, который я когда-либо писал, но он, по крайней мере, работает.

1
ответ дан 2 September 2019 в 23:45
поделиться

Я думаю, это может быть случай преждевременной оптимизации?

Как вы думаете, почему вам нужно выполнить компиляцию до прямого кода, а не отправлять во время выполнения?

0
ответ дан 2 September 2019 в 23:45
поделиться

Может быть, посмотрите на Любопытно повторяющийся шаблон шаблона

Что, если бы вы начали с этого

template <int pinNumber> class InputPin 
{
  static bool IsHigh()
  {
     return ( (*portAddress) & (1<<pinNumber) );
  }
};

template <int Pin> class Button 
{
  static bool IsPressed()
  {
    return !InputPin<Pin>::IsHigh();  // might need typename here
  }
};

Button < 1 > powerButton;

if (powerButton.IsPressed())

Возможно, тогда он мог бы развиться до

template <int pinNumber, typename event> class InputPin 
{
  static bool IsHigh()
  {
     event::OnA();
     return ( (*portAddress) & (1<<pinNumber) );
  }
};

template <int Pin> class Button 
{
  static bool IsPressed()
  {
    return !InputPin<Pin,Button>::IsHigh();  // might need typename here
  }

  OnA(){}
  OnB(){}
};
0
ответ дан 2 September 2019 в 23:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: